From a9123c8b69422dfff377e3b07746dec48e91dc60 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Thu, 3 Oct 2024 03:56:44 +0000 Subject: Support floating point values for layer crop Flag: EXEMPT bug fix Fixes: 310950423 Test: presubmit Change-Id: I05feb4881a95bc8caad90a3d632b3c7881909bf3 --- libs/gui/SurfaceComposerClient.cpp | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'libs/gui/SurfaceComposerClient.cpp') diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index df58df43be..21a375ec1c 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1652,6 +1652,11 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setMatri SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setCrop( const sp& sc, const Rect& crop) { + return setCrop(sc, crop.toFloatRect()); +} + +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setCrop( + const sp& sc, const FloatRect& crop) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; -- cgit v1.2.3-59-g8ed1b From 117556e09150a155c80385b315d80fb0a762416d Mon Sep 17 00:00:00 2001 From: Melody Hsu Date: Thu, 3 Oct 2024 21:58:56 +0000 Subject: Remove unecessary flag checks for Transaction#setFlags The if statement does not provide any value and is an additional area to have to maintain when introducing new flags. Bug: 371381313 Test: presubmit Flag: EXEMPT bug fix Change-Id: Ie1a929451aaa6d87e82e9ab131ddb50d2d70cee3 --- libs/gui/SurfaceComposerClient.cpp | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) (limited to 'libs/gui/SurfaceComposerClient.cpp') diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index df58df43be..b976d814b6 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1539,14 +1539,7 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFlags mStatus = BAD_INDEX; return *this; } - if ((mask & layer_state_t::eLayerOpaque) || (mask & layer_state_t::eLayerHidden) || - (mask & layer_state_t::eLayerSecure) || (mask & layer_state_t::eLayerSkipScreenshot) || - (mask & layer_state_t::eEnableBackpressure) || - (mask & layer_state_t::eIgnoreDestinationFrame) || - (mask & layer_state_t::eLayerIsDisplayDecoration) || - (mask & layer_state_t::eLayerIsRefreshRateIndicator)) { - s->what |= layer_state_t::eFlagsChanged; - } + s->what |= layer_state_t::eFlagsChanged; s->flags &= ~mask; s->flags |= (flags & mask); s->mask |= mask; -- cgit v1.2.3-59-g8ed1b From 95f669a30a74fa519dc9dc760a099d977ebee567 Mon Sep 17 00:00:00 2001 From: Sally Qi Date: Tue, 27 Aug 2024 11:31:42 -0700 Subject: [Lut HAL backend] implementation - Add Lut in HWComposer::DeviceRequestedChanges - parse lutProperties into overlayProperties - Add a mapper to store lut fd to avoid dup() ops if passing the fds into callees. - SurfaceComposerClient::Transaction::setLuts interface Bug: 329472100 Test: builds Flag: NONE HAL backend interface change Change-Id: Ib2993ce1eab66ab456388c0d15b032201eac7e91 --- libs/gui/SurfaceComposerClient.cpp | 14 ++++++++++ libs/gui/aidl/android/gui/Lut.aidl | 30 ++++++++++++++++++++ libs/gui/aidl/android/gui/LutProperties.aidl | 32 ++++++++++++++++++++++ libs/gui/aidl/android/gui/OverlayProperties.aidl | 4 +++ libs/gui/include/gui/SurfaceComposerClient.h | 5 ++++ .../include/compositionengine/OutputLayer.h | 4 +++ .../include/compositionengine/impl/Display.h | 2 ++ .../include/compositionengine/impl/OutputLayer.h | 2 ++ .../include/compositionengine/mock/OutputLayer.h | 3 ++ .../CompositionEngine/src/Display.cpp | 20 ++++++++++++++ .../CompositionEngine/src/OutputLayer.cpp | 7 +++++ .../CompositionEngine/tests/DisplayTest.cpp | 4 +++ .../CompositionEngine/tests/MockHWComposer.h | 5 +--- .../DisplayHardware/AidlComposerHal.cpp | 8 +++++- .../DisplayHardware/AidlComposerHal.h | 2 +- .../surfaceflinger/DisplayHardware/ComposerHal.h | 2 +- services/surfaceflinger/DisplayHardware/HWC2.cpp | 30 ++++++++++++++------ services/surfaceflinger/DisplayHardware/HWC2.h | 16 +++++++---- .../surfaceflinger/DisplayHardware/HWComposer.cpp | 27 ++++++++---------- .../surfaceflinger/DisplayHardware/HWComposer.h | 22 +++++++-------- .../DisplayHardware/HidlComposerHal.cpp | 3 +- .../DisplayHardware/HidlComposerHal.h | 2 +- services/surfaceflinger/SurfaceFlinger.cpp | 16 +++++++++++ .../unittests/mock/DisplayHardware/MockComposer.h | 2 +- .../unittests/mock/DisplayHardware/MockHWC2.h | 2 +- 25 files changed, 212 insertions(+), 52 deletions(-) create mode 100644 libs/gui/aidl/android/gui/Lut.aidl create mode 100644 libs/gui/aidl/android/gui/LutProperties.aidl (limited to 'libs/gui/SurfaceComposerClient.cpp') diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index df58df43be..10746e07f8 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1941,6 +1941,20 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setDesir return *this; } +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setLuts( + const sp& sc, const base::unique_fd& /*lutFd*/, + const std::vector& /*offsets*/, const std::vector& /*dimensions*/, + const std::vector& /*sizes*/, const std::vector& /*samplingKeys*/) { + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } + // TODO (b/329472856): update layer_state_t for lut(s) + registerSurfaceControlForCallback(sc); + return *this; +} + SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setCachingHint( const sp& sc, gui::CachingHint cachingHint) { layer_state_t* s = getLayerState(sc); diff --git a/libs/gui/aidl/android/gui/Lut.aidl b/libs/gui/aidl/android/gui/Lut.aidl new file mode 100644 index 0000000000..a06e521789 --- /dev/null +++ b/libs/gui/aidl/android/gui/Lut.aidl @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.gui; + +import android.gui.LutProperties; +import android.os.ParcelFileDescriptor; + +/** + * This mirrors aidl::android::hardware::graphics::composer3::Lut definition + * @hide + */ +parcelable Lut { + @nullable ParcelFileDescriptor pfd; + + LutProperties lutProperties; +} \ No newline at end of file diff --git a/libs/gui/aidl/android/gui/LutProperties.aidl b/libs/gui/aidl/android/gui/LutProperties.aidl new file mode 100644 index 0000000000..561e0c069c --- /dev/null +++ b/libs/gui/aidl/android/gui/LutProperties.aidl @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.gui; + +/** + * This mirrors aidl::android::hardware::graphics::composer3::LutProperties definition. + * @hide + */ +parcelable LutProperties { + @Backing(type="int") + enum Dimension { ONE_D = 1, THREE_D = 3 } + Dimension dimension; + + long size; + @Backing(type="int") + enum SamplingKey { RGB, MAX_RGB } + SamplingKey[] samplingKeys; +} \ No newline at end of file diff --git a/libs/gui/aidl/android/gui/OverlayProperties.aidl b/libs/gui/aidl/android/gui/OverlayProperties.aidl index 5fb1a83c65..7f41bdab2f 100644 --- a/libs/gui/aidl/android/gui/OverlayProperties.aidl +++ b/libs/gui/aidl/android/gui/OverlayProperties.aidl @@ -16,6 +16,8 @@ package android.gui; +import android.gui.LutProperties; + /** @hide */ parcelable OverlayProperties { parcelable SupportedBufferCombinations { @@ -27,4 +29,6 @@ parcelable OverlayProperties { SupportedBufferCombinations[] combinations; boolean supportMixedColorSpaces; + + @nullable LutProperties[] lutProperties; } diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 4f9af16826..88c7e9300d 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -601,6 +601,11 @@ public: Transaction& setExtendedRangeBrightness(const sp& sc, float currentBufferRatio, float desiredRatio); Transaction& setDesiredHdrHeadroom(const sp& sc, float desiredRatio); + Transaction& setLuts(const sp& sc, const base::unique_fd& lutFd, + const std::vector& offsets, + const std::vector& dimensions, + const std::vector& sizes, + const std::vector& samplingKeys); Transaction& setCachingHint(const sp& sc, gui::CachingHint cachingHint); Transaction& setHdrMetadata(const sp& sc, const HdrMetadata& hdrMetadata); Transaction& setSurfaceDamageRegion(const sp& sc, diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h index 4dbf8d2fce..dcfe21a849 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h @@ -128,6 +128,10 @@ public: // Applies a HWC device layer request virtual void applyDeviceLayerRequest(Hwc2::IComposerClient::LayerRequest request) = 0; + // Applies a HWC device layer lut + virtual void applyDeviceLayerLut(aidl::android::hardware::graphics::composer3::LutProperties, + ndk::ScopedFileDescriptor) = 0; + // Returns true if the composition settings scale pixels virtual bool needsFiltering() const = 0; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h index d1eff241d3..a39abb40d2 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h @@ -82,11 +82,13 @@ public: using DisplayRequests = android::HWComposer::DeviceRequestedChanges::DisplayRequests; using LayerRequests = android::HWComposer::DeviceRequestedChanges::LayerRequests; using ClientTargetProperty = android::HWComposer::DeviceRequestedChanges::ClientTargetProperty; + using LayerLuts = android::HWComposer::DeviceRequestedChanges::LayerLuts; virtual bool allLayersRequireClientComposition() const; virtual void applyChangedTypesToLayers(const ChangedTypes&); virtual void applyDisplayRequests(const DisplayRequests&); virtual void applyLayerRequestsToLayers(const LayerRequests&); virtual void applyClientTargetRequests(const ClientTargetProperty&); + virtual void applyLayerLutsToLayers(const LayerLuts&); // Internal virtual void setConfiguration(const compositionengine::DisplayCreationArgs&); diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h index f383392e55..354a4416f2 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h @@ -60,6 +60,8 @@ public: aidl::android::hardware::graphics::composer3::Composition) override; void prepareForDeviceLayerRequests() override; void applyDeviceLayerRequest(Hwc2::IComposerClient::LayerRequest request) override; + void applyDeviceLayerLut(aidl::android::hardware::graphics::composer3::LutProperties, + ndk::ScopedFileDescriptor) override; bool needsFiltering() const override; std::optional getOverrideCompositionSettings() const override; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h index 5fef63a510..48c2f9c483 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h @@ -56,6 +56,9 @@ public: MOCK_METHOD1(applyDeviceLayerRequest, void(Hwc2::IComposerClient::LayerRequest request)); MOCK_CONST_METHOD0(needsFiltering, bool()); MOCK_CONST_METHOD0(getOverrideCompositionSettings, std::optional()); + MOCK_METHOD(void, applyDeviceLayerLut, + (aidl::android::hardware::graphics::composer3::LutProperties, + ndk::ScopedFileDescriptor)); MOCK_CONST_METHOD1(dump, void(std::string&)); }; diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp index 77b1940e23..b0164b7c33 100644 --- a/services/surfaceflinger/CompositionEngine/src/Display.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp @@ -278,6 +278,7 @@ void Display::applyCompositionStrategy(const std::optionaldisplayRequests); applyLayerRequestsToLayers(changes->layerRequests); applyClientTargetRequests(changes->clientTargetProperty); + applyLayerLutsToLayers(changes->layerLuts); } // Determine what type of composition we are doing from the final state @@ -359,6 +360,25 @@ void Display::applyClientTargetRequests(const ClientTargetProperty& clientTarget static_cast(clientTargetProperty.clientTargetProperty.pixelFormat)); } +void Display::applyLayerLutsToLayers(const LayerLuts& layerLuts) { + auto& mapper = getCompositionEngine().getHwComposer().getLutFileDescriptorMapper(); + for (auto* layer : getOutputLayersOrderedByZ()) { + auto hwcLayer = layer->getHwcLayer(); + if (!hwcLayer) { + continue; + } + + if (auto lutsIt = layerLuts.find(hwcLayer); lutsIt != layerLuts.end()) { + if (auto mapperIt = mapper.find(hwcLayer); mapperIt != mapper.end()) { + layer->applyDeviceLayerLut(lutsIt->second, + ndk::ScopedFileDescriptor(mapperIt->second.release())); + } + } + } + + mapper.clear(); +} + void Display::executeCommands() { const auto halDisplayIdOpt = HalDisplayId::tryCast(mId); if (mIsDisconnected || !halDisplayIdOpt) { diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp index 091c207464..07bbb00073 100644 --- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp +++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp @@ -37,6 +37,7 @@ #pragma clang diagnostic pop // ignored "-Wconversion" using aidl::android::hardware::graphics::composer3::Composition; +using aidl::android::hardware::graphics::composer3::LutProperties; namespace android::compositionengine { @@ -844,6 +845,12 @@ void OutputLayer::applyDeviceLayerRequest(hal::LayerRequest request) { } } +void OutputLayer::applyDeviceLayerLut(LutProperties /*lutProperties*/, + ndk::ScopedFileDescriptor /*lutPfd*/) { + // TODO(b/329472856): decode the shared memory of the pfd, and store the lut data into + // OutputLayerCompositionState#hwc struct +} + bool OutputLayer::needsFiltering() const { const auto& state = getState(); const auto& sourceCrop = state.sourceCrop; diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp index 39163ea60f..9c0e62c643 100644 --- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp @@ -133,6 +133,7 @@ struct DisplayTestCommon : public testing::Test { MOCK_METHOD1(applyChangedTypesToLayers, void(const impl::Display::ChangedTypes&)); MOCK_METHOD1(applyDisplayRequests, void(const impl::Display::DisplayRequests&)); MOCK_METHOD1(applyLayerRequestsToLayers, void(const impl::Display::LayerRequests&)); + MOCK_METHOD1(applyLayerLutsToLayers, void(const impl::Display::LayerLuts&)); const compositionengine::CompositionEngine& mCompositionEngine; impl::OutputCompositionState mState; @@ -212,6 +213,7 @@ struct PartialMockDisplayTestCommon : public DisplayTestCommon { aidl::android::hardware::graphics::common::Dataspace::UNKNOWN}, -1.f, DimmingStage::NONE}, + {}, }; void chooseCompositionStrategy(Display* display) { @@ -615,6 +617,7 @@ TEST_F(DisplayChooseCompositionStrategyTest, normalOperation) { EXPECT_CALL(*mDisplay, applyLayerRequestsToLayers(mDeviceRequestedChanges.layerRequests)) .Times(1); EXPECT_CALL(*mDisplay, allLayersRequireClientComposition()).WillOnce(Return(false)); + EXPECT_CALL(*mDisplay, applyLayerLutsToLayers(mDeviceRequestedChanges.layerLuts)).Times(1); chooseCompositionStrategy(mDisplay.get()); @@ -667,6 +670,7 @@ TEST_F(DisplayChooseCompositionStrategyTest, normalOperationWithChanges) { EXPECT_CALL(*mDisplay, applyLayerRequestsToLayers(mDeviceRequestedChanges.layerRequests)) .Times(1); EXPECT_CALL(*mDisplay, allLayersRequireClientComposition()).WillOnce(Return(false)); + EXPECT_CALL(*mDisplay, applyLayerLutsToLayers(mDeviceRequestedChanges.layerLuts)).Times(1); chooseCompositionStrategy(mDisplay.get()); diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h index e910c72e2e..5c55ce739a 100644 --- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h +++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h @@ -152,10 +152,7 @@ public: getOverlaySupport, (), (const, override)); MOCK_METHOD(status_t, setRefreshRateChangedCallbackDebugEnabled, (PhysicalDisplayId, bool)); MOCK_METHOD(status_t, notifyExpectedPresent, (PhysicalDisplayId, TimePoint, Fps)); - MOCK_METHOD(status_t, getRequestedLuts, - (PhysicalDisplayId, - std::vector*), - (override)); + MOCK_METHOD((HWC2::Display::LutFileDescriptorMapper&), getLutFileDescriptorMapper, (), ()); }; } // namespace mock diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp index 66237b9d8a..77bd8040c5 100644 --- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp +++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp @@ -1547,7 +1547,8 @@ Error AidlComposer::getClientTargetProperty( return error; } -Error AidlComposer::getRequestedLuts(Display display, std::vector* outLuts) { +Error AidlComposer::getRequestedLuts(Display display, std::vector* outLayers, + std::vector* outLuts) { Error error = Error::NONE; mMutex.lock_shared(); if (auto reader = getReader(display)) { @@ -1556,6 +1557,11 @@ Error AidlComposer::getRequestedLuts(Display display, std::vectorreserve(outLuts->size()); + for (const auto& layerLut : *outLuts) { + outLayers->emplace_back(translate(layerLut.layer)); + } return error; } diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h index 246223a668..cdb67e4e5c 100644 --- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h +++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h @@ -245,7 +245,7 @@ public: Error notifyExpectedPresent(Display, nsecs_t expectedPresentTime, int32_t frameIntervalNs) override; Error getRequestedLuts( - Display display, + Display display, std::vector* outLayers, std::vector* outLuts) override; Error setLayerLuts( diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h index 7db9a94e54..09056631d0 100644 --- a/services/surfaceflinger/DisplayHardware/ComposerHal.h +++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h @@ -305,7 +305,7 @@ public: virtual Error setRefreshRateChangedCallbackDebugEnabled(Display, bool) = 0; virtual Error notifyExpectedPresent(Display, nsecs_t expectedPresentTime, int32_t frameIntervalNs) = 0; - virtual Error getRequestedLuts(Display display, + virtual Error getRequestedLuts(Display display, std::vector* outLayers, std::vector* outLuts) = 0; virtual Error setLayerLuts(Display display, Layer layer, std::vector& luts) = 0; }; diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp index f1fa9389eb..1df2ab12ce 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.cpp +++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp @@ -609,17 +609,29 @@ Error Display::getClientTargetProperty( return static_cast(error); } -Error Display::getRequestedLuts(std::vector* outLayerLuts) { - std::vector tmpLayerLuts; - const auto error = mComposer.getRequestedLuts(mId, &tmpLayerLuts); - for (DisplayLuts::LayerLut& layerLut : tmpLayerLuts) { - if (layerLut.lut.pfd.get() >= 0) { - outLayerLuts->push_back({layerLut.layer, - Lut{ndk::ScopedFileDescriptor(layerLut.lut.pfd.release()), - layerLut.lut.lutProperties}}); +Error Display::getRequestedLuts(LayerLuts* outLuts, + LutFileDescriptorMapper& lutFileDescriptorMapper) { + std::vector layerIds; + std::vector tmpLuts; + const auto error = static_cast(mComposer.getRequestedLuts(mId, &layerIds, &tmpLuts)); + if (error != Error::NONE) { + return error; + } + + uint32_t numElements = layerIds.size(); + outLuts->clear(); + for (uint32_t i = 0; i < numElements; ++i) { + auto layer = getLayerById(layerIds[i]); + if (layer) { + auto& layerLut = tmpLuts[i]; + outLuts->emplace_or_replace(layer.get(), layerLut.lut.lutProperties); + lutFileDescriptorMapper.emplace_or_replace(layer.get(), + ndk::ScopedFileDescriptor( + layerLut.lut.pfd.release())); } } - return static_cast(error); + + return Error::NONE; } Error Display::getDisplayDecorationSupport( diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h index 8e2aeaf234..61f92f4d74 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.h +++ b/services/surfaceflinger/DisplayHardware/HWC2.h @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -107,6 +108,13 @@ public: virtual void onLayerDestroyed(hal::HWLayerId layerId) = 0; virtual std::optional getPhysicalSizeInMm() const = 0; + static const int kLutFileDescriptorMapperSize = 20; + using LayerLuts = + ftl::SmallMap; + using LutFileDescriptorMapper = + ftl::SmallMap; + [[nodiscard]] virtual hal::Error acceptChanges() = 0; [[nodiscard]] virtual base::expected, hal::Error> createLayer() = 0; @@ -183,8 +191,7 @@ public: aidl::android::hardware::graphics::composer3::ClientTargetPropertyWithBrightness* outClientTargetProperty) = 0; [[nodiscard]] virtual hal::Error getRequestedLuts( - std::vector* - outLuts) = 0; + LayerLuts* outLuts, LutFileDescriptorMapper& lutFileDescriptorMapper) = 0; [[nodiscard]] virtual hal::Error getDisplayDecorationSupport( std::optional* support) = 0; @@ -268,9 +275,8 @@ public: hal::Error getClientTargetProperty( aidl::android::hardware::graphics::composer3::ClientTargetPropertyWithBrightness* outClientTargetProperty) override; - hal::Error getRequestedLuts( - std::vector* - outLuts) override; + hal::Error getRequestedLuts(LayerLuts* outLuts, + LutFileDescriptorMapper& lutFileDescriptorMapper) override; hal::Error getDisplayDecorationSupport( std::optional* support) override; diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp index bd093f52cf..edce805a7e 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -587,9 +587,14 @@ status_t HWComposer::getDeviceCompositionChanges( error = hwcDisplay->getClientTargetProperty(&clientTargetProperty); RETURN_IF_HWC_ERROR_FOR("getClientTargetProperty", error, displayId, BAD_INDEX); + DeviceRequestedChanges::LayerLuts layerLuts; + error = hwcDisplay->getRequestedLuts(&layerLuts, mLutFileDescriptorMapper); + RETURN_IF_HWC_ERROR_FOR("getRequestedLuts", error, displayId, BAD_INDEX); + outChanges->emplace(DeviceRequestedChanges{std::move(changedTypes), std::move(displayRequests), std::move(layerRequests), - std::move(clientTargetProperty)}); + std::move(clientTargetProperty), + std::move(layerLuts)}); error = hwcDisplay->acceptChanges(); RETURN_IF_HWC_ERROR_FOR("acceptChanges", error, displayId, BAD_INDEX); @@ -978,21 +983,6 @@ status_t HWComposer::getDisplayDecorationSupport( return NO_ERROR; } -status_t HWComposer::getRequestedLuts( - PhysicalDisplayId displayId, - std::vector* outLuts) { - RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX); - const auto error = mDisplayData[displayId].hwcDisplay->getRequestedLuts(outLuts); - if (error == hal::Error::UNSUPPORTED) { - RETURN_IF_HWC_ERROR(error, displayId, INVALID_OPERATION); - } - if (error == hal::Error::BAD_PARAMETER) { - RETURN_IF_HWC_ERROR(error, displayId, BAD_VALUE); - } - RETURN_IF_HWC_ERROR(error, displayId, UNKNOWN_ERROR); - return NO_ERROR; -} - status_t HWComposer::setAutoLowLatencyMode(PhysicalDisplayId displayId, bool on) { RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX); const auto error = mDisplayData[displayId].hwcDisplay->setAutoLowLatencyMode(on); @@ -1036,6 +1026,11 @@ const std::unordered_map& HWComposer::getSupportedLayerGeneri return mSupportedLayerGenericMetadata; } +ftl::SmallMap& +HWComposer::getLutFileDescriptorMapper() { + return mLutFileDescriptorMapper; +} + void HWComposer::dumpOverlayProperties(std::string& result) const { // dump overlay properties result.append("OverlayProperties:\n"); diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h index b95c619f75..7b04d6755a 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.h +++ b/services/surfaceflinger/DisplayHardware/HWComposer.h @@ -53,6 +53,7 @@ #include #include #include +#include #include namespace android { @@ -90,11 +91,14 @@ public: aidl::android::hardware::graphics::composer3::ClientTargetPropertyWithBrightness; using DisplayRequests = hal::DisplayRequest; using LayerRequests = std::unordered_map; + using LutProperties = aidl::android::hardware::graphics::composer3::LutProperties; + using LayerLuts = HWC2::Display::LayerLuts; ChangedTypes changedTypes; DisplayRequests displayRequests; LayerRequests layerRequests; ClientTargetProperty clientTargetProperty; + LayerLuts layerLuts; }; struct HWCDisplayMode { @@ -311,18 +315,15 @@ public: virtual status_t setRefreshRateChangedCallbackDebugEnabled(PhysicalDisplayId, bool enabled) = 0; virtual status_t notifyExpectedPresent(PhysicalDisplayId, TimePoint expectedPresentTime, Fps frameInterval) = 0; - - // Composer 4.0 - virtual status_t getRequestedLuts( - PhysicalDisplayId, - std::vector*) = 0; + // mapper + virtual HWC2::Display::LutFileDescriptorMapper& getLutFileDescriptorMapper() = 0; }; static inline bool operator==(const android::HWComposer::DeviceRequestedChanges& lhs, const android::HWComposer::DeviceRequestedChanges& rhs) { return lhs.changedTypes == rhs.changedTypes && lhs.displayRequests == rhs.displayRequests && lhs.layerRequests == rhs.layerRequests && - lhs.clientTargetProperty == rhs.clientTargetProperty; + lhs.clientTargetProperty == rhs.clientTargetProperty && lhs.layerLuts == rhs.layerLuts; } namespace impl { @@ -480,11 +481,8 @@ public: status_t notifyExpectedPresent(PhysicalDisplayId, TimePoint expectedPresentTime, Fps frameInterval) override; - // Composer 4.0 - status_t getRequestedLuts( - PhysicalDisplayId, - std::vector*) - override; + // get a mapper + HWC2::Display::LutFileDescriptorMapper& getLutFileDescriptorMapper() override; // for debugging ---------------------------------------------------------- void dump(std::string& out) const override; @@ -571,6 +569,8 @@ private: const size_t mMaxVirtualDisplayDimension; const bool mUpdateDeviceProductInfoOnHotplugReconnect; bool mEnableVrrTimeout; + + HWC2::Display::LutFileDescriptorMapper mLutFileDescriptorMapper; }; } // namespace impl diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp index ee1e07ae7d..056ecd78f4 100644 --- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp +++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp @@ -1410,7 +1410,8 @@ Error HidlComposer::getClientTargetProperty( return Error::NONE; } -Error HidlComposer::getRequestedLuts(Display, std::vector*) { +Error HidlComposer::getRequestedLuts(Display, std::vector*, + std::vector*) { return Error::NONE; } diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h index 701a54bc66..1cc23d1409 100644 --- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h +++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h @@ -352,7 +352,7 @@ public: Error setRefreshRateChangedCallbackDebugEnabled(Display, bool) override; Error notifyExpectedPresent(Display, nsecs_t, int32_t) override; Error getRequestedLuts( - Display, + Display, std::vector*, std::vector*) override; Error setLayerLuts(Display, Layer, diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 4bfbde5f28..a50c344de4 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1648,6 +1648,22 @@ status_t SurfaceFlinger::getOverlaySupport(gui::OverlayProperties* outProperties outProperties->combinations.emplace_back(outCombination); } outProperties->supportMixedColorSpaces = aidlProperties.supportMixedColorSpaces; + if (aidlProperties.lutProperties.has_value()) { + std::vector outLutProperties; + for (const auto& properties : aidlProperties.lutProperties.value()) { + gui::LutProperties currentProperties; + currentProperties.dimension = + static_cast(properties->dimension); + currentProperties.size = properties->size; + currentProperties.samplingKeys.reserve(properties->samplingKeys.size()); + std::transform(properties->samplingKeys.cbegin(), properties->samplingKeys.cend(), + std::back_inserter(currentProperties.samplingKeys), [](const auto& val) { + return static_cast(val); + }); + outLutProperties.push_back(std::move(currentProperties)); + } + outProperties->lutProperties.emplace(outLutProperties.begin(), outLutProperties.end()); + } return NO_ERROR; } diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h index f472d8fefe..615cc948ed 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h @@ -182,7 +182,7 @@ public: MOCK_METHOD(Error, notifyExpectedPresent, (Display, nsecs_t, int32_t)); MOCK_METHOD( Error, getRequestedLuts, - (Display, + (Display, std::vector*, std::vector*)); MOCK_METHOD(Error, setLayerLuts, (Display, Layer, std::vector&)); diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h index 5edd2cd9e3..53ed2e1f20 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h @@ -111,7 +111,7 @@ public: (aidl::android::hardware::graphics::composer3::OverlayProperties *), (const override)); MOCK_METHOD(hal::Error, getRequestedLuts, - (std::vector*), + ((HWC2::Display::LayerLuts*), (HWC2::Display::LutFileDescriptorMapper&)), (override)); }; -- cgit v1.2.3-59-g8ed1b From 89fbb6e4b6eeb24662072ba627f05281c50d2d14 Mon Sep 17 00:00:00 2001 From: ramindani Date: Thu, 26 Sep 2024 11:30:24 -0700 Subject: Adds hasArrSupport api support BUG: 361433651 Test: Test: atest DisplayModeDirectorTest && atest BrightnessObserverTest && atest SettingsObserverTest Flag: com.android.server.display.feature.flags.enable_has_arr_support Change-Id: Ie9f16c229a22d404acd70ae9898fe3feacbcd6dc --- libs/gui/SurfaceComposerClient.cpp | 1 + libs/gui/aidl/android/gui/DynamicDisplayInfo.aidl | 3 +++ libs/ui/include/ui/DynamicDisplayInfo.h | 2 ++ services/surfaceflinger/SurfaceFlinger.cpp | 2 ++ 4 files changed, 8 insertions(+) (limited to 'libs/gui/SurfaceComposerClient.cpp') diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 063aabbdef..eeea80fa82 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -2807,6 +2807,7 @@ void SurfaceComposerClient::getDynamicDisplayInfoInternal(gui::DynamicDisplayInf outInfo->autoLowLatencyModeSupported = ginfo.autoLowLatencyModeSupported; outInfo->gameContentTypeSupported = ginfo.gameContentTypeSupported; outInfo->preferredBootDisplayMode = ginfo.preferredBootDisplayMode; + outInfo->hasArrSupport = ginfo.hasArrSupport; } status_t SurfaceComposerClient::getDynamicDisplayInfoFromId(int64_t displayId, diff --git a/libs/gui/aidl/android/gui/DynamicDisplayInfo.aidl b/libs/gui/aidl/android/gui/DynamicDisplayInfo.aidl index 3114929e86..70873b001b 100644 --- a/libs/gui/aidl/android/gui/DynamicDisplayInfo.aidl +++ b/libs/gui/aidl/android/gui/DynamicDisplayInfo.aidl @@ -43,4 +43,7 @@ parcelable DynamicDisplayInfo { // The boot display mode preferred by the implementation. int preferredBootDisplayMode; + + // Represents whether display supports ARR. + boolean hasArrSupport; } diff --git a/libs/ui/include/ui/DynamicDisplayInfo.h b/libs/ui/include/ui/DynamicDisplayInfo.h index 0b77754455..25a2b6ee53 100644 --- a/libs/ui/include/ui/DynamicDisplayInfo.h +++ b/libs/ui/include/ui/DynamicDisplayInfo.h @@ -53,6 +53,8 @@ struct DynamicDisplayInfo { ui::DisplayModeId preferredBootDisplayMode; std::optional getActiveDisplayMode() const; + + bool hasArrSupport; }; } // namespace android::ui diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index a821e3d494..a2a16a1092 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1215,6 +1215,7 @@ void SurfaceFlinger::getDynamicDisplayInfoInternal(ui::DynamicDisplayInfo*& info const auto mode = display->refreshRateSelector().getActiveMode(); info->activeDisplayModeId = ftl::to_underlying(mode.modePtr->getId()); info->renderFrameRate = mode.fps.getValue(); + info->hasArrSupport = mode.modePtr->getVrrConfig() && FlagManager::getInstance().vrr_config(); info->activeColorMode = display->getCompositionDisplay()->getState().colorMode; info->hdrCapabilities = filterOut4k30(display->getHdrCapabilities()); @@ -8640,6 +8641,7 @@ void SurfaceComposerAIDL::getDynamicDisplayInfoInternal(ui::DynamicDisplayInfo& outInfo->activeDisplayModeId = info.activeDisplayModeId; outInfo->renderFrameRate = info.renderFrameRate; + outInfo->hasArrSupport = info.hasArrSupport; outInfo->supportedColorModes.clear(); outInfo->supportedColorModes.reserve(info.supportedColorModes.size()); -- cgit v1.2.3-59-g8ed1b From 0abc4a5897fdd556f2a618400eff4f9677649024 Mon Sep 17 00:00:00 2001 From: Sally Qi Date: Thu, 26 Sep 2024 16:13:06 -0700 Subject: [Lut HAL backend] implementation 2nd patch 1. add gui/DisplayLuts.h structure. Mimic DisplayLuts.java. 2. add Lut parameter into Layer side. When SurfaceControl#setLuts is called, in native code, the lut information is passed to SurfaceFlinger and RenderEngine side via LayerState::eLutsChanged. 3. in OutputLayer::updateCompositionState, we compare the Lut requested from the app and the Lut from the HWC to decide GPU composition or not. 4. DPU or GPU composition? If the Lut from the app exactly matches the Lut from the hwc, do DPU. Otherwise, GPU composition instead. Bug: 329472856 Test: libcompositionengine_test Flag: NONE HAL backend interface change Change-Id: I8295fe419c6237d90b7ff9f02f62bafd6cd2cecf --- libs/gui/LayerState.cpp | 6 ++ libs/gui/SurfaceComposerClient.cpp | 13 ++- libs/gui/aidl/android/gui/Lut.aidl | 30 ------ libs/gui/aidl/android/gui/LutProperties.aidl | 2 +- libs/gui/include/gui/DisplayLuts.h | 54 ++++++++++ libs/gui/include/gui/LayerState.h | 6 +- .../include/renderengine/LayerSettings.h | 5 +- .../compositionengine/LayerFECompositionState.h | 4 + .../include/compositionengine/Output.h | 2 + .../include/compositionengine/OutputLayer.h | 11 +- .../include/compositionengine/impl/Display.h | 2 + .../include/compositionengine/impl/Output.h | 2 + .../include/compositionengine/impl/OutputLayer.h | 13 ++- .../impl/OutputLayerCompositionState.h | 4 + .../include/compositionengine/mock/Output.h | 2 + .../include/compositionengine/mock/OutputLayer.h | 10 +- .../CompositionEngine/src/Display.cpp | 9 +- .../CompositionEngine/src/Output.cpp | 9 +- .../CompositionEngine/src/OutputLayer.cpp | 113 +++++++++++++++++++-- .../CompositionEngine/tests/MockHWC2.h | 4 +- .../CompositionEngine/tests/OutputTest.cpp | 45 ++++---- .../DisplayHardware/AidlComposerHal.cpp | 4 +- .../DisplayHardware/AidlComposerHal.h | 5 +- .../surfaceflinger/DisplayHardware/ComposerHal.h | 3 +- services/surfaceflinger/DisplayHardware/HWC2.cpp | 21 ++-- services/surfaceflinger/DisplayHardware/HWC2.h | 12 +-- .../DisplayHardware/HidlComposerHal.cpp | 4 +- .../DisplayHardware/HidlComposerHal.h | 2 +- services/surfaceflinger/FrontEnd/LayerSnapshot.cpp | 4 + services/surfaceflinger/LayerFE.cpp | 1 + services/surfaceflinger/SurfaceFlinger.cpp | 27 ++--- .../unittests/mock/DisplayHardware/MockComposer.h | 2 +- .../unittests/mock/DisplayHardware/MockHWC2.h | 4 +- 33 files changed, 320 insertions(+), 115 deletions(-) delete mode 100644 libs/gui/aidl/android/gui/Lut.aidl create mode 100644 libs/gui/include/gui/DisplayLuts.h (limited to 'libs/gui/SurfaceComposerClient.cpp') diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 422c57bc87..4b531345b0 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -664,6 +664,10 @@ void layer_state_t::merge(const layer_state_t& other) { what |= eShadowRadiusChanged; shadowRadius = other.shadowRadius; } + if (other.what & eLutsChanged) { + what |= eLutsChanged; + luts = other.luts; + } if (other.what & eDefaultFrameRateCompatibilityChanged) { what |= eDefaultFrameRateCompatibilityChanged; defaultFrameRateCompatibility = other.defaultFrameRateCompatibility; @@ -821,6 +825,8 @@ uint64_t layer_state_t::diff(const layer_state_t& other) const { CHECK_DIFF(diff, eColorSpaceAgnosticChanged, other, colorSpaceAgnostic); CHECK_DIFF(diff, eDimmingEnabledChanged, other, dimmingEnabled); if (other.what & eBufferReleaseChannelChanged) diff |= eBufferReleaseChannelChanged; + if (other.what & eLutsChanged) diff |= eLutsChanged; + return diff; } diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 063aabbdef..ebad069602 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -1940,15 +1941,19 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setDesir } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setLuts( - const sp& sc, const base::unique_fd& /*lutFd*/, - const std::vector& /*offsets*/, const std::vector& /*dimensions*/, - const std::vector& /*sizes*/, const std::vector& /*samplingKeys*/) { + const sp& sc, const base::unique_fd& lutFd, + const std::vector& offsets, const std::vector& dimensions, + const std::vector& sizes, const std::vector& samplingKeys) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; return *this; } - // TODO (b/329472856): update layer_state_t for lut(s) + + s->luts = std::make_shared(base::unique_fd(dup(lutFd.get())), offsets, + dimensions, sizes, samplingKeys); + s->what |= layer_state_t::eLutsChanged; + registerSurfaceControlForCallback(sc); return *this; } diff --git a/libs/gui/aidl/android/gui/Lut.aidl b/libs/gui/aidl/android/gui/Lut.aidl deleted file mode 100644 index a06e521789..0000000000 --- a/libs/gui/aidl/android/gui/Lut.aidl +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2024 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.gui; - -import android.gui.LutProperties; -import android.os.ParcelFileDescriptor; - -/** - * This mirrors aidl::android::hardware::graphics::composer3::Lut definition - * @hide - */ -parcelable Lut { - @nullable ParcelFileDescriptor pfd; - - LutProperties lutProperties; -} \ No newline at end of file diff --git a/libs/gui/aidl/android/gui/LutProperties.aidl b/libs/gui/aidl/android/gui/LutProperties.aidl index 561e0c069c..87b878c1ca 100644 --- a/libs/gui/aidl/android/gui/LutProperties.aidl +++ b/libs/gui/aidl/android/gui/LutProperties.aidl @@ -25,7 +25,7 @@ parcelable LutProperties { enum Dimension { ONE_D = 1, THREE_D = 3 } Dimension dimension; - long size; + int size; @Backing(type="int") enum SamplingKey { RGB, MAX_RGB } SamplingKey[] samplingKeys; diff --git a/libs/gui/include/gui/DisplayLuts.h b/libs/gui/include/gui/DisplayLuts.h new file mode 100644 index 0000000000..16a360dcee --- /dev/null +++ b/libs/gui/include/gui/DisplayLuts.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +#include +#include + +namespace android::gui { + +struct DisplayLuts { +public: + struct Entry { + int32_t dimension; + int32_t size; + int32_t samplingKey; + }; + + DisplayLuts() {} + + DisplayLuts(base::unique_fd lutfd, std::vector lutoffsets, + std::vector lutdimensions, std::vector lutsizes, + std::vector lutsamplingKeys) { + fd = std::move(lutfd); + offsets = lutoffsets; + lutProperties.reserve(offsets.size()); + for (size_t i = 0; i < lutoffsets.size(); i++) { + Entry entry{lutdimensions[i], lutsizes[i], lutsamplingKeys[i]}; + lutProperties.emplace_back(entry); + } + } + + base::unique_fd& getLutFileDescriptor() { return fd; } + + std::vector lutProperties; + std::vector offsets; + +private: + base::unique_fd fd; +}; // struct DisplayLuts + +} // namespace android::gui \ No newline at end of file diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index 00065c81d8..6bfeaec26a 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -184,6 +185,7 @@ struct layer_state_t { eCachingHintChanged = 0x00000200, eDimmingEnabledChanged = 0x00000400, eShadowRadiusChanged = 0x00000800, + eLutsChanged = 0x00001000, eBufferCropChanged = 0x00002000, eRelativeLayerChanged = 0x00004000, eReparent = 0x00008000, @@ -255,7 +257,7 @@ struct layer_state_t { layer_state_t::eTransformToDisplayInverseChanged | layer_state_t::eTransparentRegionChanged | layer_state_t::eExtendedRangeBrightnessChanged | - layer_state_t::eDesiredHdrHeadroomChanged; + layer_state_t::eDesiredHdrHeadroomChanged | layer_state_t::eLutsChanged; // Content updates. static constexpr uint64_t CONTENT_CHANGES = layer_state_t::BUFFER_CHANGES | @@ -416,6 +418,8 @@ struct layer_state_t { TrustedPresentationListener trustedPresentationListener; std::shared_ptr bufferReleaseChannel; + + std::shared_ptr luts; }; class ComposerState { diff --git a/libs/renderengine/include/renderengine/LayerSettings.h b/libs/renderengine/include/renderengine/LayerSettings.h index 859ae8b6e2..ac43da8dcf 100644 --- a/libs/renderengine/include/renderengine/LayerSettings.h +++ b/libs/renderengine/include/renderengine/LayerSettings.h @@ -16,6 +16,7 @@ #pragma once +#include #include #include #include @@ -145,6 +146,8 @@ struct LayerSettings { // If white point nits are unknown, then this layer is assumed to have the // same luminance as the brightest layer in the scene. float whitePointNits = -1.f; + + std::shared_ptr luts; }; // Keep in sync with custom comparison function in @@ -187,7 +190,7 @@ static inline bool operator==(const LayerSettings& lhs, const LayerSettings& rhs lhs.blurRegionTransform == rhs.blurRegionTransform && lhs.stretchEffect == rhs.stretchEffect && lhs.edgeExtensionEffect == rhs.edgeExtensionEffect && - lhs.whitePointNits == rhs.whitePointNits; + lhs.whitePointNits == rhs.whitePointNits && lhs.luts == rhs.luts; } static inline void PrintTo(const Buffer& settings, ::std::ostream* os) { diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h index 14a8fd6ad7..8a91a07115 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -219,6 +220,9 @@ struct LayerFECompositionState { float desiredHdrSdrRatio = 1.f; gui::CachingHint cachingHint = gui::CachingHint::Enabled; + + std::shared_ptr luts; + virtual ~LayerFECompositionState(); // Debugging diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h index 191d475e5d..556aa249a3 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h @@ -329,6 +329,8 @@ protected: virtual bool isPowerHintSessionGpuReportingEnabled() = 0; virtual void cacheClientCompositionRequests(uint32_t cacheSize) = 0; virtual bool canPredictCompositionStrategy(const CompositionRefreshArgs&) = 0; + virtual const aidl::android::hardware::graphics::composer3::OverlayProperties* + getOverlaySupport() = 0; }; } // namespace compositionengine diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h index dcfe21a849..80c5124c76 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h @@ -93,7 +93,10 @@ public: // transform, if needed. virtual void updateCompositionState( bool includeGeometry, bool forceClientComposition, - ui::Transform::RotationFlags internalDisplayRotationFlags) = 0; + ui::Transform::RotationFlags internalDisplayRotationFlags, + const std::optional>> + properties) = 0; // Writes the geometry state to the HWC, or does nothing if this layer does // not use the HWC. If includeGeometry is false, the geometry state can be @@ -129,8 +132,10 @@ public: virtual void applyDeviceLayerRequest(Hwc2::IComposerClient::LayerRequest request) = 0; // Applies a HWC device layer lut - virtual void applyDeviceLayerLut(aidl::android::hardware::graphics::composer3::LutProperties, - ndk::ScopedFileDescriptor) = 0; + virtual void applyDeviceLayerLut( + ndk::ScopedFileDescriptor, + std::vector>) = 0; // Returns true if the composition settings scale pixels virtual bool needsFiltering() const = 0; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h index a39abb40d2..d8466ffdff 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h @@ -103,6 +103,8 @@ private: DisplayId mId; bool mIsDisconnected = false; Hwc2::PowerAdvisor* mPowerAdvisor = nullptr; + const aidl::android::hardware::graphics::composer3::OverlayProperties* getOverlaySupport() + override; }; // This template factory function standardizes the implementation details of the diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h index 9990a742db..69e1efc4a7 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h @@ -164,6 +164,8 @@ protected: bool mustRecompose() const; const std::string& getNamePlusId() const { return mNamePlusId; } + const aidl::android::hardware::graphics::composer3::OverlayProperties* getOverlaySupport() + override; private: void dirtyEntireOutput(); diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h index 354a4416f2..0c7e4dd071 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h @@ -31,6 +31,8 @@ #include +using aidl::android::hardware::graphics::composer3::LutProperties; + namespace android::compositionengine { struct LayerFECompositionState; @@ -48,7 +50,9 @@ public: void uncacheBuffers(const std::vector& bufferIdsToUncache) override; void updateCompositionState(bool includeGeometry, bool forceClientComposition, - ui::Transform::RotationFlags) override; + ui::Transform::RotationFlags, + const std::optional>> + properties = std::nullopt) override; void writeStateToHWC(bool includeGeometry, bool skipLayer, uint32_t z, bool zIsOverridden, bool isPeekingThrough) override; void writeCursorPositionToHWC() const override; @@ -60,8 +64,8 @@ public: aidl::android::hardware::graphics::composer3::Composition) override; void prepareForDeviceLayerRequests() override; void applyDeviceLayerRequest(Hwc2::IComposerClient::LayerRequest request) override; - void applyDeviceLayerLut(aidl::android::hardware::graphics::composer3::LutProperties, - ndk::ScopedFileDescriptor) override; + void applyDeviceLayerLut(ndk::ScopedFileDescriptor, + std::vector>) override; bool needsFiltering() const override; std::optional getOverrideCompositionSettings() const override; @@ -92,10 +96,13 @@ private: void writeCompositionTypeToHWC(HWC2::Layer*, aidl::android::hardware::graphics::composer3::Composition, bool isPeekingThrough, bool skipLayer); + void writeLutToHWC(HWC2::Layer*, const LayerFECompositionState&); void detectDisallowedCompositionTypeChange( aidl::android::hardware::graphics::composer3::Composition from, aidl::android::hardware::graphics::composer3::Composition to) const; bool isClientCompositionForced(bool isPeekingThrough) const; + void updateLuts(std::shared_ptr luts, + const std::optional>>& properties); }; // This template factory function standardizes the implementation details of the diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h index 6c419da716..28216a475c 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -151,6 +152,9 @@ struct OutputLayerCompositionState { // True when this layer was skipped as part of SF-side layer caching. bool layerSkipped = false; + + // lut information + std::shared_ptr luts; }; // The HWC state is optional, and is only set up if there is any potential diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h index d5bf2b5090..33cdc54b90 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h @@ -140,6 +140,8 @@ public: MOCK_METHOD(void, setHintSessionRequiresRenderEngine, (bool requiresRenderEngine)); MOCK_METHOD(bool, isPowerHintSessionEnabled, ()); MOCK_METHOD(bool, isPowerHintSessionGpuReportingEnabled, ()); + MOCK_METHOD((const aidl::android::hardware::graphics::composer3::OverlayProperties*), + getOverlaySupport, ()); }; } // namespace android::compositionengine::mock diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h index 48c2f9c483..12f20942cb 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h @@ -43,7 +43,10 @@ public: MOCK_CONST_METHOD0(getState, const impl::OutputLayerCompositionState&()); MOCK_METHOD0(editState, impl::OutputLayerCompositionState&()); - MOCK_METHOD3(updateCompositionState, void(bool, bool, ui::Transform::RotationFlags)); + MOCK_METHOD(void, updateCompositionState, + (bool, bool, ui::Transform::RotationFlags, + (const std::optional>>))); MOCK_METHOD5(writeStateToHWC, void(bool, bool, uint32_t, bool, bool)); MOCK_CONST_METHOD0(writeCursorPositionToHWC, void()); @@ -57,8 +60,9 @@ public: MOCK_CONST_METHOD0(needsFiltering, bool()); MOCK_CONST_METHOD0(getOverrideCompositionSettings, std::optional()); MOCK_METHOD(void, applyDeviceLayerLut, - (aidl::android::hardware::graphics::composer3::LutProperties, - ndk::ScopedFileDescriptor)); + (ndk::ScopedFileDescriptor, + (std::vector>))); MOCK_CONST_METHOD1(dump, void(std::string&)); }; diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp index b0164b7c33..1825065c8f 100644 --- a/services/surfaceflinger/CompositionEngine/src/Display.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp @@ -370,8 +370,8 @@ void Display::applyLayerLutsToLayers(const LayerLuts& layerLuts) { if (auto lutsIt = layerLuts.find(hwcLayer); lutsIt != layerLuts.end()) { if (auto mapperIt = mapper.find(hwcLayer); mapperIt != mapper.end()) { - layer->applyDeviceLayerLut(lutsIt->second, - ndk::ScopedFileDescriptor(mapperIt->second.release())); + layer->applyDeviceLayerLut(ndk::ScopedFileDescriptor(mapperIt->second.release()), + lutsIt->second); } } } @@ -457,6 +457,11 @@ void Display::setHintSessionRequiresRenderEngine(bool requiresRenderEngine) { mPowerAdvisor->setRequiresRenderEngine(mId, requiresRenderEngine); } +const aidl::android::hardware::graphics::composer3::OverlayProperties* +Display::getOverlaySupport() { + return &getCompositionEngine().getHwComposer().getOverlaySupport(); +} + void Display::finishFrame(GpuCompositionResult&& result) { // We only need to actually compose the display if: // 1) It is being handled by hardware composer, which may need this to diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index 2d8f98f2a4..58c82db0bd 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -813,11 +813,14 @@ void Output::updateCompositionState(const compositionengine::CompositionRefreshA mLayerRequestingBackgroundBlur = findLayerRequestingBackgroundComposition(); bool forceClientComposition = mLayerRequestingBackgroundBlur != nullptr; + auto* properties = getOverlaySupport(); + for (auto* layer : getOutputLayersOrderedByZ()) { layer->updateCompositionState(refreshArgs.updatingGeometryThisFrame, refreshArgs.devOptForceClientComposition || forceClientComposition, - refreshArgs.internalDisplayRotationFlags); + refreshArgs.internalDisplayRotationFlags, + properties ? properties->lutProperties : std::nullopt); if (mLayerRequestingBackgroundBlur == layer) { forceClientComposition = false; @@ -1689,6 +1692,10 @@ void Output::setTreat170mAsSrgb(bool enable) { editState().treat170mAsSrgb = enable; } +const aidl::android::hardware::graphics::composer3::OverlayProperties* Output::getOverlaySupport() { + return nullptr; +} + bool Output::canPredictCompositionStrategy(const CompositionRefreshArgs& refreshArgs) { uint64_t lastOutputLayerHash = getState().lastOutputLayerHash; uint64_t outputLayerHash = getState().outputLayerHash; diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp index 2d46dc0702..934909d066 100644 --- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp +++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp @@ -38,7 +38,7 @@ #pragma clang diagnostic pop // ignored "-Wconversion" using aidl::android::hardware::graphics::composer3::Composition; -using aidl::android::hardware::graphics::composer3::LutProperties; +using aidl::android::hardware::graphics::composer3::Luts; namespace android::compositionengine { @@ -285,9 +285,50 @@ uint32_t OutputLayer::calculateOutputRelativeBufferTransform( return transform.getOrientation(); } +void OutputLayer::updateLuts( + std::shared_ptr layerFEStateLut, + const std::optional>>& properties) { + auto& state = editState(); + + if (!properties) { + // GPU composition if no Hwc Luts + state.forceClientComposition = true; + return; + } + + std::vector hwcLutProperties; + for (auto& p : *properties) { + if (p) { + hwcLutProperties.emplace_back(*p); + } + } + + for (const auto& inputLut : layerFEStateLut->lutProperties) { + bool foundInHwcLuts = false; + for (const auto& hwcLut : hwcLutProperties) { + if (static_cast(hwcLut.dimension) == + static_cast(inputLut.dimension) && + hwcLut.size == inputLut.size && + std::find(hwcLut.samplingKeys.begin(), hwcLut.samplingKeys.end(), + static_cast(inputLut.samplingKey)) != + hwcLut.samplingKeys.end()) { + foundInHwcLuts = true; + break; + } + } + // if any lut properties of layerFEStateLut can not be found in hwcLutProperties, + // GPU composition instead + if (!foundInHwcLuts) { + state.forceClientComposition = true; + return; + } + } +} + void OutputLayer::updateCompositionState( bool includeGeometry, bool forceClientComposition, - ui::Transform::RotationFlags internalDisplayRotationFlags) { + ui::Transform::RotationFlags internalDisplayRotationFlags, + const std::optional>> properties) { const auto* layerFEState = getLayerFE().getCompositionState(); if (!layerFEState) { return; @@ -368,6 +409,11 @@ void OutputLayer::updateCompositionState( state.whitePointNits = layerBrightnessNits; } + const auto& layerFEStateLut = layerFEState->luts; + if (layerFEStateLut) { + updateLuts(layerFEStateLut, properties); + } + // These are evaluated every frame as they can potentially change at any // time. if (layerFEState->forceClientComposition || !profile.isDataspaceSupported(state.dataspace) || @@ -420,6 +466,8 @@ void OutputLayer::writeStateToHWC(bool includeGeometry, bool skipLayer, uint32_t writeCompositionTypeToHWC(hwcLayer.get(), requestedCompositionType, isPeekingThrough, skipLayer); + writeLutToHWC(hwcLayer.get(), *outputIndependentState); + if (requestedCompositionType == Composition::SOLID_COLOR) { writeSolidColorStateToHWC(hwcLayer.get(), *outputIndependentState); } @@ -513,6 +561,40 @@ void OutputLayer::writeOutputIndependentGeometryStateToHWC( } } +void OutputLayer::writeLutToHWC(HWC2::Layer* hwcLayer, + const LayerFECompositionState& outputIndependentState) { + if (!outputIndependentState.luts) { + return; + } + auto& lutFileDescriptor = outputIndependentState.luts->getLutFileDescriptor(); + auto lutOffsets = outputIndependentState.luts->offsets; + auto& lutProperties = outputIndependentState.luts->lutProperties; + + std::vector aidlProperties; + aidlProperties.reserve(lutProperties.size()); + for (size_t i = 0; i < lutOffsets.size(); i++) { + LutProperties properties; + properties.dimension = static_cast(lutProperties[i].dimension); + properties.size = lutProperties[i].size; + properties.samplingKeys = { + static_cast(lutProperties[i].samplingKey)}; + aidlProperties.emplace_back(properties); + } + + Luts luts; + luts.pfd = ndk::ScopedFileDescriptor(dup(lutFileDescriptor.get())); + luts.offsets = lutOffsets; + luts.lutProperties = std::move(aidlProperties); + + switch (auto error = hwcLayer->setLuts(luts)) { + case hal::Error::NONE: + break; + default: + ALOGE("[%s] Failed to set Luts: %s (%d)", getLayerFE().getDebugName(), + to_string(error).c_str(), static_cast(error)); + } +} + void OutputLayer::writeOutputDependentPerFrameStateToHWC(HWC2::Layer* hwcLayer) { const auto& outputDependentState = getState(); @@ -849,10 +931,29 @@ void OutputLayer::applyDeviceLayerRequest(hal::LayerRequest request) { } } -void OutputLayer::applyDeviceLayerLut(LutProperties /*lutProperties*/, - ndk::ScopedFileDescriptor /*lutPfd*/) { - // TODO(b/329472856): decode the shared memory of the pfd, and store the lut data into - // OutputLayerCompositionState#hwc struct +void OutputLayer::applyDeviceLayerLut( + ndk::ScopedFileDescriptor lutFileDescriptor, + std::vector> lutOffsetsAndProperties) { + auto& state = editState(); + LOG_FATAL_IF(!state.hwc); + auto& hwcState = *state.hwc; + std::vector offsets; + std::vector dimensions; + std::vector sizes; + std::vector samplingKeys; + for (const auto& [offset, properties] : lutOffsetsAndProperties) { + // The Lut(s) that comes back through CommandResultPayload should be + // only one sampling key. + if (properties.samplingKeys.size() == 1) { + offsets.emplace_back(offset); + dimensions.emplace_back(static_cast(properties.dimension)); + sizes.emplace_back(static_cast(properties.size)); + samplingKeys.emplace_back(static_cast(properties.samplingKeys[0])); + } + } + hwcState.luts = std::make_shared(base::unique_fd(lutFileDescriptor.release()), + std::move(offsets), std::move(dimensions), + std::move(sizes), std::move(samplingKeys)); } bool OutputLayer::needsFiltering() const { diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h b/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h index eb6e677117..26b5f4aaed 100644 --- a/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h +++ b/services/surfaceflinger/CompositionEngine/tests/MockHWC2.h @@ -33,7 +33,7 @@ #include "DisplayHardware/HWC2.h" #include -#include +#include // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic pop // ignored "-Wconversion -Wextra" @@ -78,7 +78,7 @@ public: Error(const std::string&, bool, const std::vector&)); MOCK_METHOD1(setBrightness, Error(float)); MOCK_METHOD1(setBlockingRegion, Error(const android::Region&)); - MOCK_METHOD(Error, setLuts, (std::vector&)); + MOCK_METHOD(Error, setLuts, (aidl::android::hardware::graphics::composer3::Luts&)); }; } // namespace mock diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp index c34168d025..e3a799ce03 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp @@ -786,17 +786,20 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, updatesLayerContentForAllLayers InjectedLayer layer3; uint32_t z = 0; - EXPECT_CALL(*layer1.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_180)); + EXPECT_CALL(*layer1.outputLayer, + updateCompositionState(false, false, ui::Transform::ROT_180, _)); EXPECT_CALL(*layer1.outputLayer, writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); EXPECT_CALL(*layer1.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); - EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_180)); + EXPECT_CALL(*layer2.outputLayer, + updateCompositionState(false, false, ui::Transform::ROT_180, _)); EXPECT_CALL(*layer2.outputLayer, writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); EXPECT_CALL(*layer2.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); - EXPECT_CALL(*layer3.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_180)); + EXPECT_CALL(*layer3.outputLayer, + updateCompositionState(false, false, ui::Transform::ROT_180, _)); EXPECT_CALL(*layer3.outputLayer, writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); @@ -823,17 +826,17 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, updatesLayerGeometryAndContentF InjectedLayer layer3; uint32_t z = 0; - EXPECT_CALL(*layer1.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0)); + EXPECT_CALL(*layer1.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer1.outputLayer, writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, z++, /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); EXPECT_CALL(*layer1.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); - EXPECT_CALL(*layer2.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0)); + EXPECT_CALL(*layer2.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer2.outputLayer, writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, z++, /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); EXPECT_CALL(*layer2.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); - EXPECT_CALL(*layer3.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0)); + EXPECT_CALL(*layer3.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer3.outputLayer, writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, z++, /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); @@ -859,17 +862,17 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, forcesClientCompositionForAllLa InjectedLayer layer3; uint32_t z = 0; - EXPECT_CALL(*layer1.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0)); + EXPECT_CALL(*layer1.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer1.outputLayer, writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); EXPECT_CALL(*layer1.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); - EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0)); + EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer2.outputLayer, writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); EXPECT_CALL(*layer2.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); - EXPECT_CALL(*layer3.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0)); + EXPECT_CALL(*layer3.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer3.outputLayer, writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); @@ -897,11 +900,11 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, peekThroughLayerChangesOrder) { InjectedLayer layer3; InSequence seq; - EXPECT_CALL(*layer0.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0)); - EXPECT_CALL(*layer1.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0)); + EXPECT_CALL(*layer0.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0, _)); + EXPECT_CALL(*layer1.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer1.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); - EXPECT_CALL(*layer2.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0)); - EXPECT_CALL(*layer3.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0)); + EXPECT_CALL(*layer2.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0, _)); + EXPECT_CALL(*layer3.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0, _)); uint32_t z = 0; EXPECT_CALL(*layer0.outputLayer, @@ -5066,12 +5069,12 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, noBackgroundBlurWhenOpaque) { uint32_t z = 0; // Layer requesting blur, or below, should request client composition, unless opaque. - EXPECT_CALL(*layer1.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_0)); + EXPECT_CALL(*layer1.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer1.outputLayer, writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); EXPECT_CALL(*layer1.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); - EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_0)); + EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer2.outputLayer, writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); @@ -5100,17 +5103,17 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, handlesBackgroundBlurRequests) uint32_t z = 0; // Layer requesting blur, or below, should request client composition. - EXPECT_CALL(*layer1.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0)); + EXPECT_CALL(*layer1.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer1.outputLayer, writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); EXPECT_CALL(*layer1.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); - EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0)); + EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer2.outputLayer, writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); EXPECT_CALL(*layer2.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); - EXPECT_CALL(*layer3.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_0)); + EXPECT_CALL(*layer3.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer3.outputLayer, writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); @@ -5140,17 +5143,17 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, handlesBlurRegionRequests) { uint32_t z = 0; // Layer requesting blur, or below, should request client composition. - EXPECT_CALL(*layer1.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0)); + EXPECT_CALL(*layer1.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer1.outputLayer, writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); EXPECT_CALL(*layer1.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); - EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0)); + EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer2.outputLayer, writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); EXPECT_CALL(*layer2.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); - EXPECT_CALL(*layer3.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_0)); + EXPECT_CALL(*layer3.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer3.outputLayer, writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp index 77bd8040c5..5814aa4354 100644 --- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp +++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp @@ -44,7 +44,7 @@ using hardware::Return; using aidl::android::hardware::graphics::composer3::BnComposerCallback; using aidl::android::hardware::graphics::composer3::Capability; using aidl::android::hardware::graphics::composer3::ClientTargetPropertyWithBrightness; -using aidl::android::hardware::graphics::composer3::Lut; +using aidl::android::hardware::graphics::composer3::Luts; using aidl::android::hardware::graphics::composer3::PowerMode; using aidl::android::hardware::graphics::composer3::VirtualDisplay; @@ -1565,7 +1565,7 @@ Error AidlComposer::getRequestedLuts(Display display, std::vector* outLay return error; } -Error AidlComposer::setLayerLuts(Display display, Layer layer, std::vector& luts) { +Error AidlComposer::setLayerLuts(Display display, Layer layer, Luts& luts) { Error error = Error::NONE; mMutex.lock_shared(); if (auto writer = getWriter(display)) { diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h index cdb67e4e5c..d724b218c0 100644 --- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h +++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h @@ -53,6 +53,7 @@ using aidl::android::hardware::graphics::common::HdrConversionCapability; using aidl::android::hardware::graphics::common::HdrConversionStrategy; using aidl::android::hardware::graphics::composer3::ComposerClientReader; using aidl::android::hardware::graphics::composer3::ComposerClientWriter; +using aidl::android::hardware::graphics::composer3::Luts; using aidl::android::hardware::graphics::composer3::OverlayProperties; class AidlIComposerCallbackWrapper; @@ -248,9 +249,7 @@ public: Display display, std::vector* outLayers, std::vector* outLuts) override; - Error setLayerLuts( - Display display, Layer layer, - std::vector& luts) override; + Error setLayerLuts(Display display, Layer layer, Luts& luts) override; private: // Many public functions above simply write a command into the command diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h index 09056631d0..42ddcd18c8 100644 --- a/services/surfaceflinger/DisplayHardware/ComposerHal.h +++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h @@ -42,7 +42,6 @@ #include #include #include -#include #include #include @@ -307,7 +306,7 @@ public: int32_t frameIntervalNs) = 0; virtual Error getRequestedLuts(Display display, std::vector* outLayers, std::vector* outLuts) = 0; - virtual Error setLayerLuts(Display display, Layer layer, std::vector& luts) = 0; + virtual Error setLayerLuts(Display display, Layer layer, V3_0::Luts& luts) = 0; }; } // namespace Hwc2 diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp index 1df2ab12ce..5355a12cda 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.cpp +++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp @@ -42,7 +42,8 @@ using aidl::android::hardware::graphics::composer3::Composition; using AidlCapability = aidl::android::hardware::graphics::composer3::Capability; using aidl::android::hardware::graphics::composer3::DisplayCapability; using aidl::android::hardware::graphics::composer3::DisplayLuts; -using aidl::android::hardware::graphics::composer3::Lut; +using aidl::android::hardware::graphics::composer3::LutProperties; +using aidl::android::hardware::graphics::composer3::Luts; using aidl::android::hardware::graphics::composer3::OverlayProperties; namespace android { @@ -624,10 +625,18 @@ Error Display::getRequestedLuts(LayerLuts* outLuts, auto layer = getLayerById(layerIds[i]); if (layer) { auto& layerLut = tmpLuts[i]; - outLuts->emplace_or_replace(layer.get(), layerLut.lut.lutProperties); - lutFileDescriptorMapper.emplace_or_replace(layer.get(), - ndk::ScopedFileDescriptor( - layerLut.lut.pfd.release())); + if (layerLut.luts.pfd.get() > 0 && layerLut.luts.offsets.has_value()) { + const auto& offsets = layerLut.luts.offsets.value(); + std::vector> lutOffsetsAndProperties; + lutOffsetsAndProperties.reserve(offsets.size()); + std::transform(offsets.begin(), offsets.end(), layerLut.luts.lutProperties.begin(), + std::back_inserter(lutOffsetsAndProperties), + [](int32_t i, LutProperties j) { return std::make_pair(i, j); }); + outLuts->emplace_or_replace(layer.get(), lutOffsetsAndProperties); + lutFileDescriptorMapper.emplace_or_replace(layer.get(), + ndk::ScopedFileDescriptor( + layerLut.luts.pfd.release())); + } } } @@ -1069,7 +1078,7 @@ Error Layer::setBlockingRegion(const Region& region) { return static_cast(intError); } -Error Layer::setLuts(std::vector& luts) { +Error Layer::setLuts(aidl::android::hardware::graphics::composer3::Luts& luts) { if (CC_UNLIKELY(!mDisplay)) { return Error::BAD_DISPLAY; } diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h index 61f92f4d74..799fd02586 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.h +++ b/services/surfaceflinger/DisplayHardware/HWC2.h @@ -46,7 +46,7 @@ #include #include #include -#include +#include #include #include @@ -109,9 +109,10 @@ public: virtual std::optional getPhysicalSizeInMm() const = 0; static const int kLutFileDescriptorMapperSize = 20; + using LutOffsetAndProperties = std::vector< + std::pair>; using LayerLuts = - ftl::SmallMap; + ftl::SmallMap; using LutFileDescriptorMapper = ftl::SmallMap; @@ -375,7 +376,7 @@ public: [[nodiscard]] virtual hal::Error setBrightness(float brightness) = 0; [[nodiscard]] virtual hal::Error setBlockingRegion(const android::Region& region) = 0; [[nodiscard]] virtual hal::Error setLuts( - std::vector& luts) = 0; + aidl::android::hardware::graphics::composer3::Luts& luts) = 0; }; namespace impl { @@ -426,8 +427,7 @@ public: // AIDL HAL hal::Error setBrightness(float brightness) override; hal::Error setBlockingRegion(const android::Region& region) override; - hal::Error setLuts( - std::vector& luts) override; + hal::Error setLuts(aidl::android::hardware::graphics::composer3::Luts&) override; private: // These are references to data owned by HWComposer, which will outlive diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp index 056ecd78f4..6a7a09b5ae 100644 --- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp +++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp @@ -47,7 +47,7 @@ using aidl::android::hardware::graphics::composer3::ClientTargetPropertyWithBrig using aidl::android::hardware::graphics::composer3::DimmingStage; using aidl::android::hardware::graphics::composer3::DisplayCapability; using aidl::android::hardware::graphics::composer3::DisplayLuts; -using aidl::android::hardware::graphics::composer3::Lut; +using aidl::android::hardware::graphics::composer3::Luts; using aidl::android::hardware::graphics::composer3::OverlayProperties; namespace android { @@ -1415,7 +1415,7 @@ Error HidlComposer::getRequestedLuts(Display, std::vector*, return Error::NONE; } -Error HidlComposer::setLayerLuts(Display, Layer, std::vector&) { +Error HidlComposer::setLayerLuts(Display, Layer, Luts&) { return Error::NONE; } diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h index 1cc23d1409..a3d1f7f291 100644 --- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h +++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h @@ -356,7 +356,7 @@ public: std::vector*) override; Error setLayerLuts(Display, Layer, - std::vector&) override; + aidl::android::hardware::graphics::composer3::Luts&) override; private: class CommandWriter : public CommandWriterBase { diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp index e5f6b7bcd1..11b674b846 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp +++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp @@ -513,6 +513,10 @@ void LayerSnapshot::merge(const RequestedLayerState& requested, bool forceUpdate isOpaque = contentOpaque && !roundedCorner.hasRoundedCorners() && color.a == 1.f; blendMode = getBlendMode(requested); } + + if (forceUpdate || requested.what & layer_state_t::eLutsChanged) { + luts = requested.luts; + } } } // namespace android::surfaceflinger::frontend diff --git a/services/surfaceflinger/LayerFE.cpp b/services/surfaceflinger/LayerFE.cpp index b05f0eecc4..2458614818 100644 --- a/services/surfaceflinger/LayerFE.cpp +++ b/services/surfaceflinger/LayerFE.cpp @@ -176,6 +176,7 @@ std::optional LayerFE::prepareClientC layerSettings.edgeExtensionEffect = mSnapshot->edgeExtensionEffect; // Record the name of the layer for debugging further down the stack. layerSettings.name = mSnapshot->name; + layerSettings.luts = mSnapshot->luts; if (hasEffect() && !hasBufferOrSidebandStream()) { prepareEffectsClientComposition(layerSettings, targetSettings); diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index a821e3d494..9b7766ff9a 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1654,19 +1654,22 @@ status_t SurfaceFlinger::getOverlaySupport(gui::OverlayProperties* outProperties outProperties->combinations.emplace_back(outCombination); } outProperties->supportMixedColorSpaces = aidlProperties.supportMixedColorSpaces; - if (aidlProperties.lutProperties.has_value()) { + if (aidlProperties.lutProperties) { std::vector outLutProperties; - for (const auto& properties : aidlProperties.lutProperties.value()) { - gui::LutProperties currentProperties; - currentProperties.dimension = - static_cast(properties->dimension); - currentProperties.size = properties->size; - currentProperties.samplingKeys.reserve(properties->samplingKeys.size()); - std::transform(properties->samplingKeys.cbegin(), properties->samplingKeys.cend(), - std::back_inserter(currentProperties.samplingKeys), [](const auto& val) { - return static_cast(val); - }); - outLutProperties.push_back(std::move(currentProperties)); + for (auto properties : *aidlProperties.lutProperties) { + if (!properties) { + gui::LutProperties currentProperties; + currentProperties.dimension = + static_cast(properties->dimension); + currentProperties.size = properties->size; + currentProperties.samplingKeys.reserve(properties->samplingKeys.size()); + std::transform(properties->samplingKeys.cbegin(), properties->samplingKeys.cend(), + std::back_inserter(currentProperties.samplingKeys), + [](const auto& val) { + return static_cast(val); + }); + outLutProperties.push_back(std::move(currentProperties)); + } } outProperties->lutProperties.emplace(outLutProperties.begin(), outLutProperties.end()); } diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h index 615cc948ed..3e6a768db8 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h @@ -185,7 +185,7 @@ public: (Display, std::vector*, std::vector*)); MOCK_METHOD(Error, setLayerLuts, - (Display, Layer, std::vector&)); + (Display, Layer, aidl::android::hardware::graphics::composer3::Luts&)); }; } // namespace Hwc2::mock diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h index 53ed2e1f20..384b908624 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h @@ -147,8 +147,8 @@ public: (const std::string &, bool, const std::vector &), (override)); MOCK_METHOD(hal::Error, setBrightness, (float), (override)); MOCK_METHOD(hal::Error, setBlockingRegion, (const android::Region &), (override)); - MOCK_METHOD(hal::Error, setLuts, - (std::vector&), (override)); + MOCK_METHOD(hal::Error, setLuts, (aidl::android::hardware::graphics::composer3::Luts&), + (override)); }; } // namespace android::HWC2::mock -- cgit v1.2.3-59-g8ed1b From 8204da2c9df74e34447cdec87ed15801272c91bf Mon Sep 17 00:00:00 2001 From: ramindani Date: Fri, 18 Oct 2024 15:22:52 -0700 Subject: Adds support for getSuggestedFrameRate api BUG: 361433796 Flag: com.android.server.display.feature.flags.enable_get_suggested_frame_rate Test: atest android.display.cts.DisplayTest Test: Check value of the frameRateCategoryRate in the `adb shell dumpsys display` Change-Id: Iabd6040d09b3fdb5ec5aa42a8aeef01d02c2fd05 --- libs/gui/SurfaceComposerClient.cpp | 3 ++ libs/gui/aidl/android/gui/DynamicDisplayInfo.aidl | 4 +++ .../aidl/android/gui/FrameRateCategoryRate.aidl | 24 +++++++++++++++ libs/ui/include/ui/DynamicDisplayInfo.h | 4 +++ libs/ui/include/ui/FrameRateCategoryRate.h | 35 ++++++++++++++++++++++ 5 files changed, 70 insertions(+) create mode 100644 libs/gui/aidl/android/gui/FrameRateCategoryRate.aidl create mode 100644 libs/ui/include/ui/FrameRateCategoryRate.h (limited to 'libs/gui/SurfaceComposerClient.cpp') diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index eeea80fa82..c52e2e1990 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -56,6 +56,7 @@ #include #include #include +#include #include #include @@ -2808,6 +2809,8 @@ void SurfaceComposerClient::getDynamicDisplayInfoInternal(gui::DynamicDisplayInf outInfo->gameContentTypeSupported = ginfo.gameContentTypeSupported; outInfo->preferredBootDisplayMode = ginfo.preferredBootDisplayMode; outInfo->hasArrSupport = ginfo.hasArrSupport; + outInfo->frameRateCategoryRate = ui::FrameRateCategoryRate(ginfo.frameRateCategoryRate.normal, + ginfo.frameRateCategoryRate.high); } status_t SurfaceComposerClient::getDynamicDisplayInfoFromId(int64_t displayId, diff --git a/libs/gui/aidl/android/gui/DynamicDisplayInfo.aidl b/libs/gui/aidl/android/gui/DynamicDisplayInfo.aidl index 70873b001b..67cc273fce 100644 --- a/libs/gui/aidl/android/gui/DynamicDisplayInfo.aidl +++ b/libs/gui/aidl/android/gui/DynamicDisplayInfo.aidl @@ -17,6 +17,7 @@ package android.gui; import android.gui.DisplayMode; +import android.gui.FrameRateCategoryRate; import android.gui.HdrCapabilities; // Information about a physical display which may change on hotplug reconnect. @@ -46,4 +47,7 @@ parcelable DynamicDisplayInfo { // Represents whether display supports ARR. boolean hasArrSupport; + + // Represents frame rate for FrameRateCategory Normal and High. + FrameRateCategoryRate frameRateCategoryRate; } diff --git a/libs/gui/aidl/android/gui/FrameRateCategoryRate.aidl b/libs/gui/aidl/android/gui/FrameRateCategoryRate.aidl new file mode 100644 index 0000000000..f30280139f --- /dev/null +++ b/libs/gui/aidl/android/gui/FrameRateCategoryRate.aidl @@ -0,0 +1,24 @@ +/* + * Copyright 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.gui; + +/** @hide */ +// Represents frame rate for FrameRateCategory Normal and High. +parcelable FrameRateCategoryRate { + float normal; + float high; +} \ No newline at end of file diff --git a/libs/ui/include/ui/DynamicDisplayInfo.h b/libs/ui/include/ui/DynamicDisplayInfo.h index 25a2b6ee53..af494dcf39 100644 --- a/libs/ui/include/ui/DynamicDisplayInfo.h +++ b/libs/ui/include/ui/DynamicDisplayInfo.h @@ -22,6 +22,7 @@ #include #include +#include #include #include @@ -55,6 +56,9 @@ struct DynamicDisplayInfo { std::optional getActiveDisplayMode() const; bool hasArrSupport; + + // Represents frame rate for FrameRateCategory Normal and High. + ui::FrameRateCategoryRate frameRateCategoryRate; }; } // namespace android::ui diff --git a/libs/ui/include/ui/FrameRateCategoryRate.h b/libs/ui/include/ui/FrameRateCategoryRate.h new file mode 100644 index 0000000000..9c392d9bc8 --- /dev/null +++ b/libs/ui/include/ui/FrameRateCategoryRate.h @@ -0,0 +1,35 @@ +/* + * Copyright 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +namespace android::ui { + +// Represents frame rate for FrameRateCategory Normal and High. +class FrameRateCategoryRate { +public: + FrameRateCategoryRate(float normal = 0, float high = 0) : mNormal(normal), mHigh(high) {} + + float getNormal() const { return mNormal; } + + float getHigh() const { return mHigh; } + +private: + float mNormal; + float mHigh; +}; + +} // namespace android::ui \ No newline at end of file -- cgit v1.2.3-59-g8ed1b From a419faaaf33e885d614d37aba02b27d2f53a37a9 Mon Sep 17 00:00:00 2001 From: Patrick Williams Date: Tue, 29 Oct 2024 16:50:27 -0500 Subject: Add warning logs when we fail to set BufferReleaseChannel Bug: 294133380 Flag: com.android.graphics.libgui.flags.buffer_release_channel Test: presubmits Change-Id: I21461ab32ae9c0e75f9cf9851737ed29e4024836 --- libs/gui/BLASTBufferQueue.cpp | 21 +++++++++++++++------ libs/gui/SurfaceComposerClient.cpp | 15 ++++++++------- libs/gui/include/gui/BLASTBufferQueue.h | 6 ++++++ 3 files changed, 29 insertions(+), 13 deletions(-) (limited to 'libs/gui/SurfaceComposerClient.cpp') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index fdc39ed765..495418b921 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -294,12 +294,7 @@ void BLASTBufferQueue::update(const sp& surface, uint32_t width, SurfaceComposerClient::Transaction t; if (surfaceControlChanged) { #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) - // SELinux policy may prevent this process from sending the BufferReleaseChannel's file - // descriptor to SurfaceFlinger, causing the entire transaction to be dropped. This - // transaction is applied separately to ensure we don't lose the other updates. - t.setApplyToken(mApplyToken) - .setBufferReleaseChannel(mSurfaceControl, mBufferReleaseProducer) - .apply(false /* synchronous */, true /* oneWay */); + updateBufferReleaseProducer(); #endif t.setFlags(mSurfaceControl, layer_state_t::eEnableBackpressure, layer_state_t::eEnableBackpressure); @@ -1335,6 +1330,20 @@ void BLASTBufferQueue::setApplyToken(sp applyToken) { #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) +void BLASTBufferQueue::updateBufferReleaseProducer() { + // SELinux policy may prevent this process from sending the BufferReleaseChannel's file + // descriptor to SurfaceFlinger, causing the entire transaction to be dropped. We send this + // transaction independently of any other updates to ensure those updates aren't lost. + SurfaceComposerClient::Transaction t; + status_t status = t.setApplyToken(mApplyToken) + .setBufferReleaseChannel(mSurfaceControl, mBufferReleaseProducer) + .apply(false /* synchronous */, true /* oneWay */); + if (status != OK) { + ALOGW("[%s] %s - failed to set buffer release channel on %s", mName.c_str(), + statusToString(status).c_str(), mSurfaceControl->getName().c_str()); + } +} + void BLASTBufferQueue::drainBufferReleaseConsumer() { ATRACE_CALL(); while (true) { diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index a93fc926c2..13e81bd723 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1347,21 +1347,22 @@ status_t SurfaceComposerClient::Transaction::apply(bool synchronous, bool oneWay sp applyToken = mApplyToken ? mApplyToken : getDefaultApplyToken(); sp sf(ComposerService::getComposerService()); - sf->setTransactionState(mFrameTimelineInfo, composerStates, displayStates, flags, applyToken, - mInputWindowCommands, mDesiredPresentTime, mIsAutoTimestamp, - mUncacheBuffers, hasListenerCallbacks, listenerCallbacks, mId, - mMergedTransactionIds); + status_t binderStatus = + sf->setTransactionState(mFrameTimelineInfo, composerStates, displayStates, flags, + applyToken, mInputWindowCommands, mDesiredPresentTime, + mIsAutoTimestamp, mUncacheBuffers, hasListenerCallbacks, + listenerCallbacks, mId, mMergedTransactionIds); mId = generateId(); // Clear the current states and flags clear(); - if (synchronous) { + if (synchronous && binderStatus == OK) { syncCallback->wait(); } mStatus = NO_ERROR; - return NO_ERROR; + return binderStatus; } sp SurfaceComposerClient::Transaction::sApplyToken = new BBinder(); @@ -1375,7 +1376,7 @@ sp SurfaceComposerClient::Transaction::getDefaultApplyToken() { void SurfaceComposerClient::Transaction::setDefaultApplyToken(sp applyToken) { std::scoped_lock lock{sApplyTokenMutex}; - sApplyToken = applyToken; + sApplyToken = std::move(applyToken); } status_t SurfaceComposerClient::Transaction::sendSurfaceFlushJankDataTransaction( diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index 4fd44e52f4..8894b66c6d 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -325,8 +325,14 @@ private: std::unique_ptr mBufferReleaseConsumer; std::shared_ptr mBufferReleaseProducer; + void updateBufferReleaseProducer() REQUIRES(mMutex); void drainBufferReleaseConsumer(); + // BufferReleaseReader is used to do blocking but interruptible reads from the buffer + // release channel. To implement this, BufferReleaseReader owns an epoll file descriptor that + // is configured to wake up when either the BufferReleaseReader::ConsumerEndpoint or an eventfd + // becomes readable. Interrupts are necessary because a free buffer may become available for + // reasons other than a buffer release from the producer. class BufferReleaseReader { public: explicit BufferReleaseReader(BLASTBufferQueue&); -- cgit v1.2.3-59-g8ed1b From c034fbf278afb6e91660754c3d6636a63a6f7bf4 Mon Sep 17 00:00:00 2001 From: Melody Hsu Date: Fri, 25 Oct 2024 22:46:40 +0000 Subject: Support SurfaceControlRegistry logs in native Log state changes in native when a transaction is merged or applied. Bug: b/366484871 Test: adb logcat to check for logs Flag: EXEMPT logging Change-Id: Iaf48b6e68743325019c2ee288b4a4648e7153627 --- libs/gui/SurfaceComposerClient.cpp | 19 +++++++++++++++++++ libs/gui/include/gui/SurfaceComposerClient.h | 3 +++ 2 files changed, 22 insertions(+) (limited to 'libs/gui/SurfaceComposerClient.cpp') diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index a93fc926c2..d7726fb83b 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -91,6 +91,7 @@ int64_t generateId() { } constexpr int64_t INVALID_VSYNC = -1; +const constexpr char* LOG_SURFACE_CONTROL_REGISTRY = "SurfaceControlRegistry"; } // namespace @@ -872,6 +873,7 @@ status_t SurfaceComposerClient::Transaction::readFromParcel(const Parcel* parcel const bool earlyWakeupEnd = parcel->readBool(); const int64_t desiredPresentTime = parcel->readInt64(); const bool isAutoTimestamp = parcel->readBool(); + const bool logCallPoints = parcel->readBool(); FrameTimelineInfo frameTimelineInfo; frameTimelineInfo.readFromParcel(parcel); @@ -999,6 +1001,7 @@ status_t SurfaceComposerClient::Transaction::writeToParcel(Parcel* parcel) const parcel->writeBool(mEarlyWakeupEnd); parcel->writeInt64(mDesiredPresentTime); parcel->writeBool(mIsAutoTimestamp); + parcel->writeBool(mLogCallPoints); mFrameTimelineInfo.writeToParcel(parcel); parcel->writeStrongBinder(mApplyToken); parcel->writeUint32(static_cast(mDisplayStates.size())); @@ -1134,6 +1137,12 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Tr mergeFrameTimelineInfo(mFrameTimelineInfo, other.mFrameTimelineInfo); + mLogCallPoints |= other.mLogCallPoints; + if (mLogCallPoints) { + ALOG(LOG_DEBUG, LOG_SURFACE_CONTROL_REGISTRY, + "Transaction %" PRIu64 " merged with transaction %" PRIu64, other.getId(), mId); + } + other.clear(); return *this; } @@ -1153,6 +1162,7 @@ void SurfaceComposerClient::Transaction::clear() { mFrameTimelineInfo = {}; mApplyToken = nullptr; mMergedTransactionIds.clear(); + mLogCallPoints = false; } uint64_t SurfaceComposerClient::Transaction::getId() { @@ -1360,6 +1370,10 @@ status_t SurfaceComposerClient::Transaction::apply(bool synchronous, bool oneWay syncCallback->wait(); } + if (mLogCallPoints) { + ALOG(LOG_DEBUG, LOG_SURFACE_CONTROL_REGISTRY, "Transaction %" PRIu64 " applied", mId); + } + mStatus = NO_ERROR; return NO_ERROR; } @@ -1390,6 +1404,11 @@ status_t SurfaceComposerClient::Transaction::sendSurfaceFlushJankDataTransaction t.registerSurfaceControlForCallback(sc); return t.apply(/*sync=*/false, /* oneWay=*/true); } + +void SurfaceComposerClient::Transaction::enableDebugLogCallPoints() { + mLogCallPoints = true; +} + // --------------------------------------------------------------------------- sp SurfaceComposerClient::createVirtualDisplay(const std::string& displayName, diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 5ea0c1619b..e9262b3870 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -437,6 +437,8 @@ public: static void mergeFrameTimelineInfo(FrameTimelineInfo& t, const FrameTimelineInfo& other); // Tracks registered callbacks sp mTransactionCompletedListener = nullptr; + // Prints debug logs when enabled. + bool mLogCallPoints = false; protected: std::unordered_map, ComposerState, IBinderHash> mComposerStates; @@ -809,6 +811,7 @@ public: static void setDefaultApplyToken(sp applyToken); static status_t sendSurfaceFlushJankDataTransaction(const sp& sc); + void enableDebugLogCallPoints(); }; status_t clearLayerFrameStats(const sp& token) const; -- cgit v1.2.3-59-g8ed1b From 87602161374f8dcede06e7280f267f77c2bee3c5 Mon Sep 17 00:00:00 2001 From: Patrick Williams Date: Tue, 5 Nov 2024 10:13:19 -0600 Subject: Update Transaction::setInputWindowInfo to take WindowInfoHandle This change allows us to reuse WindowInfoHandle objects instead of allocating a new WindowInfoHandle object for each call. Bug: 294381558 Flag: EXEMPT refactor Test: presubmits Change-Id: I39d965217763a9cacfc9e77d0723200038fd2afe --- libs/gui/SurfaceComposerClient.cpp | 4 +- libs/gui/include/gui/SurfaceComposerClient.h | 3 +- libs/gui/tests/EndToEndNativeInputTest.cpp | 107 ++++++++++++--------- services/surfaceflinger/tests/Credentials_test.cpp | 12 ++- .../tests/WindowInfosListener_test.cpp | 24 ++--- 5 files changed, 82 insertions(+), 68 deletions(-) (limited to 'libs/gui/SurfaceComposerClient.cpp') diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 3260c53a62..c97dfd4cda 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -2129,13 +2129,13 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::notifyPr } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setInputWindowInfo( - const sp& sc, const WindowInfo& info) { + const sp& sc, sp info) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; return *this; } - s->windowInfoHandle = new WindowInfoHandle(info); + s->windowInfoHandle = std::move(info); s->what |= layer_state_t::eInputInfoChanged; return *this; } diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index e9262b3870..7c6b3416f8 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -687,7 +687,8 @@ public: // ONLY FOR BLAST ADAPTER Transaction& notifyProducerDisconnect(const sp& sc); - Transaction& setInputWindowInfo(const sp& sc, const gui::WindowInfo& info); + Transaction& setInputWindowInfo(const sp& sc, + sp info); Transaction& setFocusedWindow(const gui::FocusRequest& request); Transaction& addWindowInfosReportedListener( diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp index 2f58a6cc8f..0e84d68eec 100644 --- a/libs/gui/tests/EndToEndNativeInputTest.cpp +++ b/libs/gui/tests/EndToEndNativeInputTest.cpp @@ -112,7 +112,7 @@ public: mInputFlinger = getInputFlinger(); if (noInputChannel) { - mInputInfo.setInputConfig(WindowInfo::InputConfig::NO_INPUT_CHANNEL, true); + mInputInfo->editInfo()->setInputConfig(WindowInfo::InputConfig::NO_INPUT_CHANNEL, true); } else { android::os::InputChannelCore tempChannel; android::binder::Status result = @@ -121,21 +121,21 @@ public: ADD_FAILURE() << "binder call to createInputChannel failed"; } mClientChannel = InputChannel::create(std::move(tempChannel)); - mInputInfo.token = mClientChannel->getConnectionToken(); + mInputInfo->editInfo()->token = mClientChannel->getConnectionToken(); mInputConsumer = new InputConsumer(mClientChannel); } - mInputInfo.name = "Test info"; - mInputInfo.dispatchingTimeout = 5s; - mInputInfo.globalScaleFactor = 1.0; - mInputInfo.touchableRegion.orSelf(Rect(0, 0, width, height)); + mInputInfo->editInfo()->name = "Test info"; + mInputInfo->editInfo()->dispatchingTimeout = 5s; + mInputInfo->editInfo()->globalScaleFactor = 1.0; + mInputInfo->editInfo()->touchableRegion.orSelf(Rect(0, 0, width, height)); InputApplicationInfo aInfo; aInfo.token = new BBinder(); aInfo.name = "Test app info"; aInfo.dispatchingTimeoutMillis = std::chrono::duration_cast(DISPATCHING_TIMEOUT).count(); - mInputInfo.applicationInfo = aInfo; + mInputInfo->editInfo()->applicationInfo = aInfo; } static std::unique_ptr makeColorInputSurface(const sp& scc, @@ -300,8 +300,8 @@ public: void requestFocus(ui::LogicalDisplayId displayId = ui::LogicalDisplayId::DEFAULT) { SurfaceComposerClient::Transaction t; FocusRequest request; - request.token = mInputInfo.token; - request.windowName = mInputInfo.name; + request.token = mInputInfo->getInfo()->token; + request.windowName = mInputInfo->getInfo()->name; request.timestamp = systemTime(SYSTEM_TIME_MONOTONIC); request.displayId = displayId.val(); t.setFocusedWindow(request); @@ -310,7 +310,7 @@ public: public: // But should be private - WindowInfo mInputInfo; + sp mInputInfo = sp::make(); sp mSurfaceControl; private: @@ -523,7 +523,7 @@ TEST_F(InputSurfacesTest, input_respects_surface_insets) { std::unique_ptr fgSurface = makeSurface(100, 100); bgSurface->showAt(100, 100); - fgSurface->mInputInfo.surfaceInset = 5; + fgSurface->mInputInfo->editInfo()->surfaceInset = 5; fgSurface->showAt(100, 100); injectTap(106, 106); @@ -538,8 +538,8 @@ TEST_F(InputSurfacesTest, input_respects_surface_insets_with_replaceTouchableReg std::unique_ptr fgSurface = makeSurface(100, 100); bgSurface->showAt(100, 100); - fgSurface->mInputInfo.surfaceInset = 5; - fgSurface->mInputInfo.replaceTouchableRegionWithCrop = true; + fgSurface->mInputInfo->editInfo()->surfaceInset = 5; + fgSurface->mInputInfo->editInfo()->replaceTouchableRegionWithCrop = true; fgSurface->showAt(100, 100); injectTap(106, 106); @@ -555,7 +555,7 @@ TEST_F(InputSurfacesTest, input_respects_cropped_surface_insets) { std::unique_ptr childSurface = makeSurface(100, 100); parentSurface->showAt(100, 100); - childSurface->mInputInfo.surfaceInset = 10; + childSurface->mInputInfo->editInfo()->surfaceInset = 10; childSurface->showAt(100, 100); childSurface->doTransaction([&](auto& t, auto& sc) { @@ -576,7 +576,7 @@ TEST_F(InputSurfacesTest, input_respects_scaled_surface_insets) { std::unique_ptr fgSurface = makeSurface(100, 100); bgSurface->showAt(100, 100); - fgSurface->mInputInfo.surfaceInset = 5; + fgSurface->mInputInfo->editInfo()->surfaceInset = 5; fgSurface->showAt(100, 100); fgSurface->doTransaction([&](auto& t, auto& sc) { t.setMatrix(sc, 2.0, 0, 0, 4.0); }); @@ -595,7 +595,7 @@ TEST_F(InputSurfacesTest, input_respects_scaled_surface_insets_overflow) { bgSurface->showAt(100, 100); // In case we pass the very big inset without any checking. - fgSurface->mInputInfo.surfaceInset = INT32_MAX; + fgSurface->mInputInfo->editInfo()->surfaceInset = INT32_MAX; fgSurface->showAt(100, 100); fgSurface->doTransaction([&](auto& t, auto& sc) { t.setMatrix(sc, 2.0, 0, 0, 2.0); }); @@ -608,7 +608,7 @@ TEST_F(InputSurfacesTest, input_respects_scaled_surface_insets_overflow) { TEST_F(InputSurfacesTest, touchable_region) { std::unique_ptr surface = makeSurface(100, 100); - surface->mInputInfo.touchableRegion.set(Rect{19, 29, 21, 31}); + surface->mInputInfo->editInfo()->touchableRegion.set(Rect{19, 29, 21, 31}); surface->showAt(11, 22); @@ -629,7 +629,8 @@ TEST_F(InputSurfacesTest, input_respects_touchable_region_offset_overflow) { // Since the surface is offset from the origin, the touchable region will be transformed into // display space, which would trigger an overflow or an underflow. Ensure that we are protected // against such a situation. - fgSurface->mInputInfo.touchableRegion.orSelf(Rect{INT32_MIN, INT32_MIN, INT32_MAX, INT32_MAX}); + fgSurface->mInputInfo->editInfo()->touchableRegion.orSelf( + Rect{INT32_MIN, INT32_MIN, INT32_MAX, INT32_MAX}); fgSurface->showAt(100, 100); @@ -644,7 +645,8 @@ TEST_F(InputSurfacesTest, input_respects_scaled_touchable_region_overflow) { std::unique_ptr fgSurface = makeSurface(100, 100); bgSurface->showAt(0, 0); - fgSurface->mInputInfo.touchableRegion.orSelf(Rect{INT32_MIN, INT32_MIN, INT32_MAX, INT32_MAX}); + fgSurface->mInputInfo->editInfo()->touchableRegion.orSelf( + Rect{INT32_MIN, INT32_MIN, INT32_MAX, INT32_MAX}); fgSurface->showAt(0, 0); fgSurface->doTransaction([&](auto& t, auto& sc) { t.setMatrix(sc, 2.0, 0, 0, 2.0); }); @@ -814,7 +816,7 @@ TEST_F(InputSurfacesTest, rotate_surface_with_scale) { TEST_F(InputSurfacesTest, rotate_surface_with_scale_and_insets) { std::unique_ptr surface = makeSurface(100, 100); - surface->mInputInfo.surfaceInset = 5; + surface->mInputInfo->editInfo()->surfaceInset = 5; surface->showAt(100, 100); surface->doTransaction([](auto& t, auto& sc) { @@ -843,11 +845,12 @@ TEST_F(InputSurfacesTest, touch_flag_obscured) { // Add non touchable window to fully cover touchable window. Window behind gets touch, but // with flag AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED std::unique_ptr nonTouchableSurface = makeSurface(100, 100); - nonTouchableSurface->mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, true); - nonTouchableSurface->mInputInfo.ownerUid = gui::Uid{22222}; + nonTouchableSurface->mInputInfo->editInfo() + ->setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, true); + nonTouchableSurface->mInputInfo->editInfo()->ownerUid = gui::Uid{22222}; // Overriding occlusion mode otherwise the touch would be discarded at InputDispatcher by // the default obscured/untrusted touch filter introduced in S. - nonTouchableSurface->mInputInfo.touchOcclusionMode = TouchOcclusionMode::ALLOW; + nonTouchableSurface->mInputInfo->editInfo()->touchOcclusionMode = TouchOcclusionMode::ALLOW; nonTouchableSurface->showAt(100, 100); injectTap(190, 199); @@ -863,10 +866,12 @@ TEST_F(InputSurfacesTest, touch_flag_partially_obscured_with_crop) { // AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED std::unique_ptr parentSurface = makeSurface(100, 100); std::unique_ptr nonTouchableSurface = makeSurface(100, 100); - nonTouchableSurface->mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, true); - parentSurface->mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, true); - nonTouchableSurface->mInputInfo.ownerUid = gui::Uid{22222}; - parentSurface->mInputInfo.ownerUid = gui::Uid{22222}; + nonTouchableSurface->mInputInfo->editInfo() + ->setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, true); + parentSurface->mInputInfo->editInfo()->setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, + true); + nonTouchableSurface->mInputInfo->editInfo()->ownerUid = gui::Uid{22222}; + parentSurface->mInputInfo->editInfo()->ownerUid = gui::Uid{22222}; nonTouchableSurface->showAt(0, 0); parentSurface->showAt(100, 100); @@ -887,10 +892,12 @@ TEST_F(InputSurfacesTest, touch_not_obscured_with_crop) { // the touchable window. Window behind gets touch with no obscured flags. std::unique_ptr parentSurface = makeSurface(100, 100); std::unique_ptr nonTouchableSurface = makeSurface(100, 100); - nonTouchableSurface->mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, true); - parentSurface->mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, true); - nonTouchableSurface->mInputInfo.ownerUid = gui::Uid{22222}; - parentSurface->mInputInfo.ownerUid = gui::Uid{22222}; + nonTouchableSurface->mInputInfo->editInfo() + ->setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, true); + parentSurface->mInputInfo->editInfo()->setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, + true); + nonTouchableSurface->mInputInfo->editInfo()->ownerUid = gui::Uid{22222}; + parentSurface->mInputInfo->editInfo()->ownerUid = gui::Uid{22222}; nonTouchableSurface->showAt(0, 0); parentSurface->showAt(50, 50); @@ -908,8 +915,9 @@ TEST_F(InputSurfacesTest, touch_not_obscured_with_zero_sized_bql) { std::unique_ptr bufferSurface = InputSurface::makeBufferInputSurface(mComposerClient, 0, 0); - bufferSurface->mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, true); - bufferSurface->mInputInfo.ownerUid = gui::Uid{22222}; + bufferSurface->mInputInfo->editInfo()->setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, + true); + bufferSurface->mInputInfo->editInfo()->ownerUid = gui::Uid{22222}; surface->showAt(10, 10); bufferSurface->showAt(50, 50, Rect::EMPTY_RECT); @@ -923,8 +931,9 @@ TEST_F(InputSurfacesTest, touch_not_obscured_with_zero_sized_blast) { std::unique_ptr bufferSurface = BlastInputSurface::makeBlastInputSurface(mComposerClient, 0, 0); - bufferSurface->mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, true); - bufferSurface->mInputInfo.ownerUid = gui::Uid{22222}; + bufferSurface->mInputInfo->editInfo()->setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, + true); + bufferSurface->mInputInfo->editInfo()->ownerUid = gui::Uid{22222}; surface->showAt(10, 10); bufferSurface->showAt(50, 50, Rect::EMPTY_RECT); @@ -967,13 +976,14 @@ TEST_F(InputSurfacesTest, strict_unobscured_input_scaled_without_crop_window) { TEST_F(InputSurfacesTest, strict_unobscured_input_obscured_window) { std::unique_ptr surface = makeSurface(100, 100); - surface->mInputInfo.ownerUid = gui::Uid{11111}; + surface->mInputInfo->editInfo()->ownerUid = gui::Uid{11111}; surface->doTransaction( [&](auto& t, auto& sc) { t.setDropInputMode(sc, gui::DropInputMode::OBSCURED); }); surface->showAt(100, 100); std::unique_ptr obscuringSurface = makeSurface(100, 100); - obscuringSurface->mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, true); - obscuringSurface->mInputInfo.ownerUid = gui::Uid{22222}; + obscuringSurface->mInputInfo->editInfo()->setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, + true); + obscuringSurface->mInputInfo->editInfo()->ownerUid = gui::Uid{22222}; obscuringSurface->showAt(100, 100); injectTap(101, 101); surface->assertNoEvent(); @@ -986,13 +996,14 @@ TEST_F(InputSurfacesTest, strict_unobscured_input_obscured_window) { TEST_F(InputSurfacesTest, strict_unobscured_input_partially_obscured_window) { std::unique_ptr surface = makeSurface(100, 100); - surface->mInputInfo.ownerUid = gui::Uid{11111}; + surface->mInputInfo->editInfo()->ownerUid = gui::Uid{11111}; surface->doTransaction( [&](auto& t, auto& sc) { t.setDropInputMode(sc, gui::DropInputMode::OBSCURED); }); surface->showAt(100, 100); std::unique_ptr obscuringSurface = makeSurface(100, 100); - obscuringSurface->mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, true); - obscuringSurface->mInputInfo.ownerUid = gui::Uid{22222}; + obscuringSurface->mInputInfo->editInfo()->setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, + true); + obscuringSurface->mInputInfo->editInfo()->ownerUid = gui::Uid{22222}; obscuringSurface->showAt(190, 190); injectTap(101, 101); @@ -1056,7 +1067,7 @@ TEST_F(InputSurfacesTest, ignore_touch_region_with_zero_sized_blast) { BlastInputSurface::makeBlastInputSurface(mComposerClient, 0, 0); surface->showAt(100, 100); - bufferSurface->mInputInfo.touchableRegion.orSelf(Rect(0, 0, 200, 200)); + bufferSurface->mInputInfo->editInfo()->touchableRegion.orSelf(Rect(0, 0, 200, 200)); bufferSurface->showAt(100, 100, Rect::EMPTY_RECT); injectTap(101, 101); @@ -1099,8 +1110,8 @@ TEST_F(InputSurfacesTest, cropped_container_replaces_touchable_region_with_null_ InputSurface::makeContainerInputSurface(mComposerClient, 100, 100); containerSurface->doTransaction( [&](auto& t, auto& sc) { t.reparent(sc, parentContainer->mSurfaceControl); }); - containerSurface->mInputInfo.replaceTouchableRegionWithCrop = true; - containerSurface->mInputInfo.touchableRegionCropHandle = nullptr; + containerSurface->mInputInfo->editInfo()->replaceTouchableRegionWithCrop = true; + containerSurface->mInputInfo->editInfo()->touchableRegionCropHandle = nullptr; parentContainer->showAt(10, 10, Rect(0, 0, 20, 20)); containerSurface->showAt(10, 10, Rect(0, 0, 5, 5)); @@ -1126,8 +1137,8 @@ TEST_F(InputSurfacesTest, uncropped_container_replaces_touchable_region_with_nul InputSurface::makeContainerInputSurface(mComposerClient, 100, 100); containerSurface->doTransaction( [&](auto& t, auto& sc) { t.reparent(sc, parentContainer->mSurfaceControl); }); - containerSurface->mInputInfo.replaceTouchableRegionWithCrop = true; - containerSurface->mInputInfo.touchableRegionCropHandle = nullptr; + containerSurface->mInputInfo->editInfo()->replaceTouchableRegionWithCrop = true; + containerSurface->mInputInfo->editInfo()->touchableRegionCropHandle = nullptr; parentContainer->doTransaction( [&](auto& t, auto& sc) { t.reparent(sc, bgContainer->mSurfaceControl); }); bgContainer->showAt(0, 0, Rect(0, 0, 100, 100)); @@ -1154,8 +1165,8 @@ TEST_F(InputSurfacesTest, replace_touchable_region_with_crop) { std::unique_ptr containerSurface = InputSurface::makeContainerInputSurface(mComposerClient, 100, 100); - containerSurface->mInputInfo.replaceTouchableRegionWithCrop = true; - containerSurface->mInputInfo.touchableRegionCropHandle = + containerSurface->mInputInfo->editInfo()->replaceTouchableRegionWithCrop = true; + containerSurface->mInputInfo->editInfo()->touchableRegionCropHandle = cropLayer->mSurfaceControl->getHandle(); containerSurface->showAt(10, 10, Rect::INVALID_RECT); diff --git a/services/surfaceflinger/tests/Credentials_test.cpp b/services/surfaceflinger/tests/Credentials_test.cpp index e6fed63d96..7b6e4bff6a 100644 --- a/services/surfaceflinger/tests/Credentials_test.cpp +++ b/services/surfaceflinger/tests/Credentials_test.cpp @@ -341,9 +341,9 @@ TEST_F(CredentialsTest, TransactionPermissionTest) { WindowInfosListenerUtils windowInfosListenerUtils; std::string name = "Test Layer"; sp token = sp::make(); - WindowInfo windowInfo; - windowInfo.name = name; - windowInfo.token = token; + auto windowInfo = sp::make(); + windowInfo->editInfo()->name = name; + windowInfo->editInfo()->token = token; sp surfaceControl = mComposerClient->createSurface(String8(name.c_str()), 100, 100, PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceBufferState); @@ -370,7 +370,8 @@ TEST_F(CredentialsTest, TransactionPermissionTest) { UIDFaker f(AID_SYSTEM); auto windowIsPresentAndNotTrusted = [&](const std::vector& windowInfos) { auto foundWindowInfo = - WindowInfosListenerUtils::findMatchingWindowInfo(windowInfo, windowInfos); + WindowInfosListenerUtils::findMatchingWindowInfo(*windowInfo->getInfo(), + windowInfos); if (!foundWindowInfo) { return false; } @@ -386,7 +387,8 @@ TEST_F(CredentialsTest, TransactionPermissionTest) { Transaction().setTrustedOverlay(surfaceControl, true).apply(/*synchronous=*/true); auto windowIsPresentAndTrusted = [&](const std::vector& windowInfos) { auto foundWindowInfo = - WindowInfosListenerUtils::findMatchingWindowInfo(windowInfo, windowInfos); + WindowInfosListenerUtils::findMatchingWindowInfo(*windowInfo->getInfo(), + windowInfos); if (!foundWindowInfo) { return false; } diff --git a/services/surfaceflinger/tests/WindowInfosListener_test.cpp b/services/surfaceflinger/tests/WindowInfosListener_test.cpp index ad9a674456..2dd0dd9bd3 100644 --- a/services/surfaceflinger/tests/WindowInfosListener_test.cpp +++ b/services/surfaceflinger/tests/WindowInfosListener_test.cpp @@ -50,9 +50,9 @@ protected: TEST_F(WindowInfosListenerTest, WindowInfoAddedAndRemoved) { std::string name = "Test Layer"; sp token = sp::make(); - WindowInfo windowInfo; - windowInfo.name = name; - windowInfo.token = token; + auto windowInfo = sp::make(); + windowInfo->editInfo()->name = name; + windowInfo->editInfo()->token = token; sp surfaceControl = mClient->createSurface(String8(name.c_str()), 100, 100, PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceBufferState); @@ -65,14 +65,14 @@ TEST_F(WindowInfosListenerTest, WindowInfoAddedAndRemoved) { .apply(); auto windowPresent = [&](const std::vector& windowInfos) { - return findMatchingWindowInfo(windowInfo, windowInfos); + return findMatchingWindowInfo(*windowInfo->getInfo(), windowInfos); }; ASSERT_TRUE(waitForWindowInfosPredicate(windowPresent)); Transaction().reparent(surfaceControl, nullptr).apply(); auto windowNotPresent = [&](const std::vector& windowInfos) { - return !findMatchingWindowInfo(windowInfo, windowInfos); + return !findMatchingWindowInfo(*windowInfo->getInfo(), windowInfos); }; ASSERT_TRUE(waitForWindowInfosPredicate(windowNotPresent)); } @@ -80,9 +80,9 @@ TEST_F(WindowInfosListenerTest, WindowInfoAddedAndRemoved) { TEST_F(WindowInfosListenerTest, WindowInfoChanged) { std::string name = "Test Layer"; sp token = sp::make(); - WindowInfo windowInfo; - windowInfo.name = name; - windowInfo.token = token; + auto windowInfo = sp::make(); + windowInfo->editInfo()->name = name; + windowInfo->editInfo()->token = token; sp surfaceControl = mClient->createSurface(String8(name.c_str()), 100, 100, PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceBufferState); @@ -96,7 +96,7 @@ TEST_F(WindowInfosListenerTest, WindowInfoChanged) { .apply(); auto windowIsPresentAndTouchableRegionEmpty = [&](const std::vector& windowInfos) { - auto foundWindowInfo = findMatchingWindowInfo(windowInfo, windowInfos); + auto foundWindowInfo = findMatchingWindowInfo(*windowInfo->getInfo(), windowInfos); if (!foundWindowInfo) { return false; } @@ -104,19 +104,19 @@ TEST_F(WindowInfosListenerTest, WindowInfoChanged) { }; ASSERT_TRUE(waitForWindowInfosPredicate(windowIsPresentAndTouchableRegionEmpty)); - windowInfo.addTouchableRegion({0, 0, 50, 50}); + windowInfo->editInfo()->addTouchableRegion({0, 0, 50, 50}); Transaction().setInputWindowInfo(surfaceControl, windowInfo).apply(); auto windowIsPresentAndTouchableRegionMatches = [&](const std::vector& windowInfos) { - auto foundWindowInfo = findMatchingWindowInfo(windowInfo, windowInfos); + auto foundWindowInfo = findMatchingWindowInfo(*windowInfo->getInfo(), windowInfos); if (!foundWindowInfo) { return false; } auto touchableRegion = foundWindowInfo->transform.transform(foundWindowInfo->touchableRegion); - return touchableRegion.hasSameRects(windowInfo.touchableRegion); + return touchableRegion.hasSameRects(windowInfo->getInfo()->touchableRegion); }; ASSERT_TRUE(waitForWindowInfosPredicate(windowIsPresentAndTouchableRegionMatches)); } -- cgit v1.2.3-59-g8ed1b From 07dcd4977f47e37d8dd24cf7abc32202fbe088df Mon Sep 17 00:00:00 2001 From: Brian Lindahl Date: Wed, 30 Oct 2024 11:43:23 -0600 Subject: Allow apps to apply picture profiles with priority to layers Bug: 337330263 Test: build Test: atest LayerSnapshotTest Flag: com.android.graphics.libgui.flags.apply_picture_profiles Change-Id: I1adb6069d0168084abf0a76d310abb4ffad5ce5f --- libs/gui/LayerState.cpp | 27 +++++++++++++- libs/gui/SurfaceComposerClient.cpp | 37 +++++++++++++++++-- libs/gui/include/gui/LayerState.h | 15 +++++++- libs/gui/include/gui/SurfaceComposerClient.h | 15 ++++++++ libs/ui/include/ui/PictureProfileHandle.h | 2 +- services/surfaceflinger/FrontEnd/LayerSnapshot.cpp | 7 ++++ services/surfaceflinger/SurfaceFlinger.cpp | 6 +++- .../tests/unittests/LayerSnapshotTest.cpp | 42 +++++++++++++++++++++- 8 files changed, 144 insertions(+), 7 deletions(-) (limited to 'libs/gui/SurfaceComposerClient.cpp') diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 4b531345b0..1c527d23b6 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -91,7 +92,9 @@ layer_state_t::layer_state_t() trustedOverlay(gui::TrustedOverlay::UNSET), bufferCrop(Rect::INVALID_RECT), destinationFrame(Rect::INVALID_RECT), - dropInputMode(gui::DropInputMode::NONE) { + dropInputMode(gui::DropInputMode::NONE), + pictureProfileHandle(PictureProfileHandle::NONE), + appContentPriority(0) { matrix.dsdx = matrix.dtdy = 1.0f; matrix.dsdy = matrix.dtdx = 0.0f; hdrMetadata.validTypes = 0; @@ -202,6 +205,10 @@ status_t layer_state_t::write(Parcel& output) const if (hasBufferReleaseChannel) { SAFE_PARCEL(output.writeParcelable, *bufferReleaseChannel); } +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS_APPLY_PICTURE_PROFILES + SAFE_PARCEL(output.writeInt64, pictureProfileHandle.getId()); + SAFE_PARCEL(output.writeInt32, appContentPriority); +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS_APPLY_PICTURE_PROFILES return NO_ERROR; } @@ -357,6 +364,12 @@ status_t layer_state_t::read(const Parcel& input) bufferReleaseChannel = std::make_shared(); SAFE_PARCEL(input.readParcelable, bufferReleaseChannel.get()); } +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS_APPLY_PICTURE_PROFILES + int64_t pictureProfileId; + SAFE_PARCEL(input.readInt64, &pictureProfileId); + pictureProfileHandle = PictureProfileHandle(pictureProfileId); + SAFE_PARCEL(input.readInt32, &appContentPriority); +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS_APPLY_PICTURE_PROFILES return NO_ERROR; } @@ -745,6 +758,16 @@ void layer_state_t::merge(const layer_state_t& other) { what |= eBufferReleaseChannelChanged; bufferReleaseChannel = other.bufferReleaseChannel; } + if (com_android_graphics_libgui_flags_apply_picture_profiles()) { + if (other.what & ePictureProfileHandleChanged) { + what |= ePictureProfileHandleChanged; + pictureProfileHandle = other.pictureProfileHandle; + } + if (other.what & eAppContentPriorityChanged) { + what |= eAppContentPriorityChanged; + appContentPriority = other.appContentPriority; + } + } if ((other.what & what) != other.what) { ALOGE("Unmerged SurfaceComposer Transaction properties. LayerState::merge needs updating? " "other.what=0x%" PRIX64 " what=0x%" PRIX64 " unmerged flags=0x%" PRIX64, @@ -826,6 +849,8 @@ uint64_t layer_state_t::diff(const layer_state_t& other) const { CHECK_DIFF(diff, eDimmingEnabledChanged, other, dimmingEnabled); if (other.what & eBufferReleaseChannelChanged) diff |= eBufferReleaseChannelChanged; if (other.what & eLutsChanged) diff |= eLutsChanged; + CHECK_DIFF(diff, ePictureProfileHandleChanged, other, pictureProfileHandle); + CHECK_DIFF(diff, eAppContentPriorityChanged, other, appContentPriority); return diff; } diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 3260c53a62..ebed5767a4 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -20,8 +20,6 @@ #include #include -#include - #include #include #include @@ -29,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -2447,6 +2446,40 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBuffe return *this; } +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setPictureProfileHandle( + const sp& sc, const PictureProfileHandle& pictureProfileHandle) { + if (com_android_graphics_libgui_flags_apply_picture_profiles()) { + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } + + s->what |= layer_state_t::ePictureProfileHandleChanged; + s->pictureProfileHandle = pictureProfileHandle; + + registerSurfaceControlForCallback(sc); + } + return *this; +} + +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setContentPriority( + const sp& sc, int32_t priority) { + if (com_android_graphics_libgui_flags_apply_picture_profiles()) { + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } + + s->what |= layer_state_t::eAppContentPriorityChanged; + s->appContentPriority = priority; + + registerSurfaceControlForCallback(sc); + } + return *this; +} + // --------------------------------------------------------------------------- DisplayState& SurfaceComposerClient::Transaction::getDisplayState(const sp& token) { diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index 6bfeaec26a..9098dffa8e 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -47,6 +47,7 @@ #include #include #include +#include #include #include #include @@ -224,6 +225,8 @@ struct layer_state_t { eExtendedRangeBrightnessChanged = 0x10000'00000000, eEdgeExtensionChanged = 0x20000'00000000, eBufferReleaseChannelChanged = 0x40000'00000000, + ePictureProfileHandleChanged = 0x80000'00000000, + eAppContentPriorityChanged = 0x100000'00000000, }; layer_state_t(); @@ -267,7 +270,8 @@ struct layer_state_t { layer_state_t::eColorSpaceAgnosticChanged | layer_state_t::eColorTransformChanged | layer_state_t::eCornerRadiusChanged | layer_state_t::eDimmingEnabledChanged | layer_state_t::eHdrMetadataChanged | layer_state_t::eShadowRadiusChanged | - layer_state_t::eStretchChanged; + layer_state_t::eStretchChanged | layer_state_t::ePictureProfileHandleChanged | + layer_state_t::eAppContentPriorityChanged; // Changes which invalidates the layer's visible region in CE. static constexpr uint64_t CONTENT_DIRTY = layer_state_t::CONTENT_CHANGES | @@ -412,6 +416,15 @@ struct layer_state_t { float currentHdrSdrRatio = 1.f; float desiredHdrSdrRatio = 1.f; + // Enhance the quality of the buffer contents by configurating a picture processing pipeline + // with values as specified by this picture profile. + PictureProfileHandle pictureProfileHandle{PictureProfileHandle::NONE}; + + // A value indicating the significance of the layer's content to the app's desired user + // experience. A lower priority will result in more likelihood of getting access to limited + // resources, such as picture processing hardware. + int32_t appContentPriority = 0; + gui::CachingHint cachingHint = gui::CachingHint::Enabled; TrustedPresentationThresholds trustedPresentationThresholds; diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index e9262b3870..6968d252e8 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -775,6 +776,20 @@ public: const sp& sc, const std::shared_ptr& channel); + /** + * Configures a surface control to use picture processing hardware, configured as specified + * by the picture profile, to enhance the quality of all subsequent buffer contents. + */ + Transaction& setPictureProfileHandle(const sp& sc, + const PictureProfileHandle& pictureProfileHandle); + + /** + * Configures the relative importance of the contents of the layer with respect to the app's + * user experience. A lower priority value will give the layer preferred access to limited + * resources, such as picture processing, over a layer with a higher priority value. + */ + Transaction& setContentPriority(const sp& sc, int32_t contentPriority); + status_t setDisplaySurface(const sp& token, const sp& bufferProducer); diff --git a/libs/ui/include/ui/PictureProfileHandle.h b/libs/ui/include/ui/PictureProfileHandle.h index 9b709b6155..f8406501b4 100644 --- a/libs/ui/include/ui/PictureProfileHandle.h +++ b/libs/ui/include/ui/PictureProfileHandle.h @@ -39,7 +39,7 @@ public: static const PictureProfileHandle NONE; PictureProfileHandle() { *this = NONE; } - PictureProfileHandle(PictureProfileId id) : mId(id) {} + explicit PictureProfileHandle(PictureProfileId id) : mId(id) {} PictureProfileId const& getId() const { return mId; } diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp index a8be50a074..58f6b96e57 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp +++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp @@ -413,6 +413,13 @@ void LayerSnapshot::merge(const RequestedLayerState& requested, bool forceUpdate if (forceUpdate || requested.what & layer_state_t::eCropChanged) { geomCrop = requested.crop; } + if (forceUpdate || requested.what & layer_state_t::ePictureProfileHandleChanged) { + pictureProfileHandle = requested.pictureProfileHandle; + } + if (forceUpdate || requested.what & layer_state_t::eAppContentPriorityChanged) { + // TODO(b/337330263): Also consider the system-determined priority of the app + pictureProfilePriority = requested.appContentPriority; + } if (forceUpdate || requested.what & layer_state_t::eDefaultFrameRateCompatibilityChanged) { const auto compatibility = diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index a7ab117679..0d03a6cef3 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -3558,7 +3558,9 @@ std::optional SurfaceFlinger::processHotplugConnect(PhysicalDispl } state.isProtected = true; state.displayName = std::move(info.name); - + state.maxLayerPictureProfiles = getHwComposer().getMaxLayerPictureProfiles(displayId); + state.hasPictureProcessing = + getHwComposer().hasDisplayCapability(displayId, DisplayCapability::PICTURE_PROCESSING); mCurrentState.displays.add(token, state); ALOGI("Connecting %s", displayString); return activeModeId; @@ -3719,6 +3721,8 @@ void SurfaceFlinger::processDisplayAdded(const wp& displayToken, builder.setPixels(resolution); builder.setIsSecure(state.isSecure); builder.setIsProtected(state.isProtected); + builder.setHasPictureProcessing(state.hasPictureProcessing); + builder.setMaxLayerPictureProfiles(state.maxLayerPictureProfiles); builder.setPowerAdvisor(mPowerAdvisor.get()); builder.setName(state.displayName); auto compositionDisplay = getCompositionEngine().createDisplay(builder.build()); diff --git a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp index e6b8a26487..6aec7434de 100644 --- a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp @@ -28,7 +28,6 @@ #include "ui/GraphicTypes.h" #include -#include #define UPDATE_AND_VERIFY(BUILDER, ...) \ ({ \ @@ -1985,4 +1984,45 @@ TEST_F(LayerSnapshotTest, contentDirtyWhenParentGeometryChanges) { UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER); EXPECT_FALSE(getSnapshot(1)->contentDirty); } +TEST_F(LayerSnapshotTest, shouldUpdatePictureProfileHandle) { + if (!com_android_graphics_libgui_flags_apply_picture_profiles()) { + GTEST_SKIP() << "Flag disabled, skipping test"; + } + std::vector transactions; + transactions.emplace_back(); + transactions.back().states.push_back({}); + transactions.back().states.front().layerId = 1; + transactions.back().states.front().state.layerId = 1; + transactions.back().states.front().state.what = layer_state_t::ePictureProfileHandleChanged; + transactions.back().states.front().state.pictureProfileHandle = PictureProfileHandle(3); + + mLifecycleManager.applyTransactions(transactions); + EXPECT_EQ(mLifecycleManager.getGlobalChanges(), RequestedLayerState::Changes::Content); + + update(mSnapshotBuilder); + + EXPECT_EQ(getSnapshot(1)->clientChanges, layer_state_t::ePictureProfileHandleChanged); + EXPECT_EQ(getSnapshot(1)->pictureProfileHandle, PictureProfileHandle(3)); +} + +TEST_F(LayerSnapshotTest, shouldUpdatePictureProfilePriorityFromAppContentPriority) { + if (!com_android_graphics_libgui_flags_apply_picture_profiles()) { + GTEST_SKIP() << "Flag disabled, skipping test"; + } + std::vector transactions; + transactions.emplace_back(); + transactions.back().states.push_back({}); + transactions.back().states.front().layerId = 1; + transactions.back().states.front().state.layerId = 1; + transactions.back().states.front().state.what = layer_state_t::eAppContentPriorityChanged; + transactions.back().states.front().state.appContentPriority = 3; + + mLifecycleManager.applyTransactions(transactions); + EXPECT_EQ(mLifecycleManager.getGlobalChanges(), RequestedLayerState::Changes::Content); + + update(mSnapshotBuilder); + + EXPECT_EQ(getSnapshot(1)->pictureProfilePriority, 3); +} + } // namespace android::surfaceflinger::frontend -- cgit v1.2.3-59-g8ed1b From ef006586b5e3bbbf69177958a388cb1208adf0ff Mon Sep 17 00:00:00 2001 From: Sally Qi Date: Fri, 11 Oct 2024 13:23:09 -0700 Subject: [Lut HAL backend] implementation 3rd patch. - interpret the lut and pass them into shader. Bug: 329472856 Test: builds Flag: EXEMPT no flag needed Change-Id: I005600593f4a369130bf8bcaea69300758b5ae03 --- libs/gui/Android.bp | 1 + libs/gui/DisplayLuts.cpp | 81 +++++++ libs/gui/LayerState.cpp | 15 ++ libs/gui/SurfaceComposerClient.cpp | 8 +- libs/gui/include/gui/DisplayLuts.h | 17 +- libs/renderengine/Android.bp | 1 + libs/renderengine/skia/SkiaRenderEngine.cpp | 4 + libs/renderengine/skia/SkiaRenderEngine.h | 2 + libs/renderengine/skia/filters/LutShader.cpp | 242 +++++++++++++++++++++ libs/renderengine/skia/filters/LutShader.h | 44 ++++ .../include/compositionengine/impl/OutputLayer.h | 2 +- .../CompositionEngine/src/OutputLayer.cpp | 16 +- .../FrontEnd/RequestedLayerState.cpp | 4 +- 13 files changed, 422 insertions(+), 15 deletions(-) create mode 100644 libs/gui/DisplayLuts.cpp create mode 100644 libs/renderengine/skia/filters/LutShader.cpp create mode 100644 libs/renderengine/skia/filters/LutShader.h (limited to 'libs/gui/SurfaceComposerClient.cpp') diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp index 80e148be9f..1e33abbdea 100644 --- a/libs/gui/Android.bp +++ b/libs/gui/Android.bp @@ -274,6 +274,7 @@ filegroup { "LayerMetadata.cpp", "LayerStatePermissions.cpp", "LayerState.cpp", + "DisplayLuts.cpp", "OccupancyTracker.cpp", "StreamSplitter.cpp", "ScreenCaptureResults.cpp", diff --git a/libs/gui/DisplayLuts.cpp b/libs/gui/DisplayLuts.cpp new file mode 100644 index 0000000000..80429765be --- /dev/null +++ b/libs/gui/DisplayLuts.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "include/gui/DisplayLuts.h" +#include +#include + +namespace android::gui { + +status_t DisplayLuts::Entry::readFromParcel(const android::Parcel* parcel) { + if (parcel == nullptr) { + ALOGE("%s: Null parcel", __func__); + return BAD_VALUE; + } + + SAFE_PARCEL(parcel->readInt32, &dimension); + SAFE_PARCEL(parcel->readInt32, &size); + SAFE_PARCEL(parcel->readInt32, &samplingKey); + + return OK; +} + +status_t DisplayLuts::Entry::writeToParcel(android::Parcel* parcel) const { + if (parcel == nullptr) { + ALOGE("%s: Null parcel", __func__); + return BAD_VALUE; + } + + SAFE_PARCEL(parcel->writeInt32, dimension); + SAFE_PARCEL(parcel->writeInt32, size); + SAFE_PARCEL(parcel->writeInt32, samplingKey); + + return OK; +} + +status_t DisplayLuts::readFromParcel(const android::Parcel* parcel) { + if (parcel == nullptr) { + ALOGE("%s: Null parcel", __func__); + return BAD_VALUE; + } + + SAFE_PARCEL(parcel->readUniqueFileDescriptor, &fd); + SAFE_PARCEL(parcel->readInt32Vector, &offsets); + int32_t numLutProperties; + SAFE_PARCEL(parcel->readInt32, &numLutProperties); + lutProperties.reserve(numLutProperties); + for (int32_t i = 0; i < numLutProperties; i++) { + lutProperties.push_back({}); + SAFE_PARCEL(lutProperties.back().readFromParcel, parcel); + } + return OK; +} + +status_t DisplayLuts::writeToParcel(android::Parcel* parcel) const { + if (parcel == nullptr) { + ALOGE("%s: Null parcel", __func__); + return BAD_VALUE; + } + + SAFE_PARCEL(parcel->writeUniqueFileDescriptor, fd); + SAFE_PARCEL(parcel->writeInt32Vector, offsets); + SAFE_PARCEL(parcel->writeInt32, static_cast(lutProperties.size())); + for (auto& entry : lutProperties) { + SAFE_PARCEL(entry.writeToParcel, parcel); + } + return OK; +} +} // namespace android::gui \ No newline at end of file diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 4b531345b0..139764ac0c 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -203,6 +203,12 @@ status_t layer_state_t::write(Parcel& output) const SAFE_PARCEL(output.writeParcelable, *bufferReleaseChannel); } + const bool hasLuts = (luts != nullptr); + SAFE_PARCEL(output.writeBool, hasLuts); + if (hasLuts) { + SAFE_PARCEL(output.writeParcelable, *luts); + } + return NO_ERROR; } @@ -358,6 +364,15 @@ status_t layer_state_t::read(const Parcel& input) SAFE_PARCEL(input.readParcelable, bufferReleaseChannel.get()); } + bool hasLuts; + SAFE_PARCEL(input.readBool, &hasLuts); + if (hasLuts) { + luts = std::make_shared(); + SAFE_PARCEL(input.readParcelable, luts.get()); + } else { + luts = nullptr; + } + return NO_ERROR; } diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 3260c53a62..807f8509b0 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1971,9 +1971,13 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setLuts( return *this; } - s->luts = std::make_shared(base::unique_fd(dup(lutFd.get())), offsets, - dimensions, sizes, samplingKeys); s->what |= layer_state_t::eLutsChanged; + if (lutFd.ok()) { + s->luts = std::make_shared(base::unique_fd(dup(lutFd.get())), offsets, + dimensions, sizes, samplingKeys); + } else { + s->luts = nullptr; + } registerSurfaceControlForCallback(sc); return *this; diff --git a/libs/gui/include/gui/DisplayLuts.h b/libs/gui/include/gui/DisplayLuts.h index 16a360dcee..ab86ac4af8 100644 --- a/libs/gui/include/gui/DisplayLuts.h +++ b/libs/gui/include/gui/DisplayLuts.h @@ -16,16 +16,24 @@ #pragma once #include +#include +#include #include namespace android::gui { -struct DisplayLuts { +struct DisplayLuts : public Parcelable { public: - struct Entry { + struct Entry : public Parcelable { + Entry() {}; + Entry(int32_t lutDimension, int32_t lutSize, int32_t lutSamplingKey) + : dimension(lutDimension), size(lutSize), samplingKey(lutSamplingKey) {} int32_t dimension; int32_t size; int32_t samplingKey; + + status_t writeToParcel(android::Parcel* parcel) const override; + status_t readFromParcel(const android::Parcel* parcel) override; }; DisplayLuts() {} @@ -42,7 +50,10 @@ public: } } - base::unique_fd& getLutFileDescriptor() { return fd; } + status_t writeToParcel(android::Parcel* parcel) const override; + status_t readFromParcel(const android::Parcel* parcel) override; + + const base::unique_fd& getLutFileDescriptor() const { return fd; } std::vector lutProperties; std::vector offsets; diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp index d248ea0b84..7f207f0670 100644 --- a/libs/renderengine/Android.bp +++ b/libs/renderengine/Android.bp @@ -105,6 +105,7 @@ filegroup { "skia/filters/KawaseBlurDualFilter.cpp", "skia/filters/KawaseBlurFilter.cpp", "skia/filters/LinearEffect.cpp", + "skia/filters/LutShader.cpp", "skia/filters/MouriMap.cpp", "skia/filters/StretchShaderFactory.cpp", "skia/filters/EdgeExtensionShaderFactory.cpp", diff --git a/libs/renderengine/skia/SkiaRenderEngine.cpp b/libs/renderengine/skia/SkiaRenderEngine.cpp index ec9d3efb88..5c46c9168d 100644 --- a/libs/renderengine/skia/SkiaRenderEngine.cpp +++ b/libs/renderengine/skia/SkiaRenderEngine.cpp @@ -543,6 +543,10 @@ sk_sp SkiaRenderEngine::createRuntimeEffectShader( } } + if (graphicBuffer && parameters.layer.luts) { + shader = mLutShader.lutShader(shader, parameters.layer.luts); + } + if (parameters.requiresLinearEffect) { const auto format = targetBuffer != nullptr ? std::optional( diff --git a/libs/renderengine/skia/SkiaRenderEngine.h b/libs/renderengine/skia/SkiaRenderEngine.h index b5f8898263..7be4c253e7 100644 --- a/libs/renderengine/skia/SkiaRenderEngine.h +++ b/libs/renderengine/skia/SkiaRenderEngine.h @@ -39,6 +39,7 @@ #include "filters/BlurFilter.h" #include "filters/EdgeExtensionShaderFactory.h" #include "filters/LinearEffect.h" +#include "filters/LutShader.h" #include "filters/StretchShaderFactory.h" class SkData; @@ -184,6 +185,7 @@ private: StretchShaderFactory mStretchShaderFactory; EdgeExtensionShaderFactory mEdgeExtensionShaderFactory; + LutShader mLutShader; sp mLastDrawFence; BlurFilter* mBlurFilter = nullptr; diff --git a/libs/renderengine/skia/filters/LutShader.cpp b/libs/renderengine/skia/filters/LutShader.cpp new file mode 100644 index 0000000000..cea46ef40e --- /dev/null +++ b/libs/renderengine/skia/filters/LutShader.cpp @@ -0,0 +1,242 @@ +/* + * Copyright 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "LutShader.h" + +#include +#include +#include +#include +#include + +#include "include/core/SkColorSpace.h" +#include "src/core/SkColorFilterPriv.h" + +using aidl::android::hardware::graphics::composer3::LutProperties; + +namespace android { +namespace renderengine { +namespace skia { + +static const SkString kShader = SkString(R"( + uniform shader image; + uniform shader lut; + uniform int size; + uniform int key; + uniform int dimension; + vec4 main(vec2 xy) { + float4 rgba = image.eval(xy); + float3 linear = toLinearSrgb(rgba.rgb); + if (dimension == 1) { + // RGB + if (key == 0) { + float indexR = linear.r * float(size - 1); + float indexG = linear.g * float(size - 1); + float indexB = linear.b * float(size - 1); + float gainR = lut.eval(vec2(indexR, 0.0) + 0.5).r; + float gainG = lut.eval(vec2(indexG, 0.0) + 0.5).r; + float gainB = lut.eval(vec2(indexB, 0.0) + 0.5).r; + return float4(linear.r * gainR, linear.g * gainG, linear.b * gainB, rgba.a); + // MAX_RGB + } else if (key == 1) { + float4 rgba = image.eval(xy); + float3 linear = toLinearSrgb(rgba.rgb); + float maxRGB = max(linear.r, max(linear.g, linear.b)); + float index = maxRGB * float(size - 1); + float gain = lut.eval(vec2(index, 0.0) + 0.5).r; + return float4(linear * gain, rgba.a); + } + } else if (dimension == 3) { + if (key == 0) { + float tx = linear.r * float(size - 1); + float ty = linear.g * float(size - 1); + float tz = linear.b * float(size - 1); + + // calculate lower and upper bounds for each dimension + int x = int(tx); + int y = int(ty); + int z = int(tz); + + int i000 = x + y * size + z * size * size; + int i100 = i000 + 1; + int i010 = i000 + size; + int i110 = i000 + size + 1; + int i001 = i000 + size * size; + int i101 = i000 + size * size + 1; + int i011 = i000 + size * size + size; + int i111 = i000 + size * size + size + 1; + + // get 1d normalized indices + float c000 = float(i000) / float(size * size * size); + float c100 = float(i100) / float(size * size * size); + float c010 = float(i010) / float(size * size * size); + float c110 = float(i110) / float(size * size * size); + float c001 = float(i001) / float(size * size * size); + float c101 = float(i101) / float(size * size * size); + float c011 = float(i011) / float(size * size * size); + float c111 = float(i111) / float(size * size * size); + + //TODO(b/377984618): support Tetrahedral interpolation + // perform trilinear interpolation + float3 c00 = mix(lut.eval(vec2(c000, 0.0) + 0.5).rgb, + lut.eval(vec2(c100, 0.0) + 0.5).rgb, linear.r); + float3 c01 = mix(lut.eval(vec2(c001, 0.0) + 0.5).rgb, + lut.eval(vec2(c101, 0.0) + 0.5).rgb, linear.r); + float3 c10 = mix(lut.eval(vec2(c010, 0.0) + 0.5).rgb, + lut.eval(vec2(c110, 0.0) + 0.5).rgb, linear.r); + float3 c11 = mix(lut.eval(vec2(c011, 0.0) + 0.5).rgb, + lut.eval(vec2(c111, 0.0) + 0.5).rgb, linear.r); + + float3 c0 = mix(c00, c10, linear.g); + float3 c1 = mix(c01, c11, linear.g); + + float3 val = mix(c0, c1, linear.b); + + return float4(val, rgba.a); + } + } + return rgba; + })"); + +sk_sp LutShader::generateLutShader(sk_sp input, + const std::vector& buffers, + const int32_t offset, const int32_t length, + const int32_t dimension, const int32_t size, + const int32_t samplingKey) { + SFTRACE_NAME("lut shader"); + std::vector buffer(length * 4); // 4 is for RGBA + auto d = static_cast(dimension); + if (d == LutProperties::Dimension::ONE_D) { + auto it = buffers.begin() + offset; + std::generate(buffer.begin(), buffer.end(), [it, i = 0]() mutable { + float val = (i++ % 4 == 0) ? *it++ : 0.0f; + return half(val); + }); + } else { + for (int i = 0; i < length; i++) { + buffer[i * 4] = half(buffers[offset + i]); + buffer[i * 4 + 1] = half(buffers[offset + length + i]); + buffer[i * 4 + 2] = half(buffers[offset + length * 2 + i]); + buffer[i * 4 + 3] = half(0); + } + } + /** + * 1D Lut(rgba) + * (R0, 0, 0, 0) + * (R1, 0, 0, 0) + * ... + * + * 3D Lut + * (R0, G0, B0, 0) + * (R1, G1, B1, 0) + * ... + */ + SkImageInfo info = SkImageInfo::Make(length /* the number of rgba */ * 4, 1, + kRGBA_F16_SkColorType, kPremul_SkAlphaType); + SkBitmap bitmap; + bitmap.allocPixels(info); + if (!bitmap.installPixels(info, buffer.data(), info.minRowBytes())) { + LOG_ALWAYS_FATAL("unable to install pixels"); + } + + sk_sp lutImage = SkImages::RasterFromBitmap(bitmap); + mBuilder->child("image") = input; + mBuilder->child("lut") = + lutImage->makeRawShader(SkTileMode::kClamp, SkTileMode::kClamp, + d == LutProperties::Dimension::ONE_D + ? SkSamplingOptions(SkFilterMode::kLinear) + : SkSamplingOptions()); + + const int uSize = static_cast(size); + const int uKey = static_cast(samplingKey); + const int uDimension = static_cast(dimension); + mBuilder->uniform("size") = uSize; + mBuilder->uniform("key") = uKey; + mBuilder->uniform("dimension") = uDimension; + return mBuilder->makeShader(); +} + +sk_sp LutShader::lutShader(sk_sp& input, + std::shared_ptr displayLuts) { + if (mBuilder == nullptr) { + const static SkRuntimeEffect::Result instance = SkRuntimeEffect::MakeForShader(kShader); + mBuilder = std::make_unique(instance.effect); + } + + auto& fd = displayLuts->getLutFileDescriptor(); + if (fd.ok()) { + // de-gamma the image without changing the primaries + SkImage* baseImage = input->isAImage((SkMatrix*)nullptr, (SkTileMode*)nullptr); + if (baseImage) { + sk_sp baseColorSpace = + baseImage->colorSpace() ? baseImage->refColorSpace() : SkColorSpace::MakeSRGB(); + sk_sp gainmapMathColorSpace = baseColorSpace->makeLinearGamma(); + auto colorXformSdrToGainmap = + SkColorFilterPriv::MakeColorSpaceXform(baseColorSpace, gainmapMathColorSpace); + input = input->makeWithColorFilter(colorXformSdrToGainmap); + } + + auto& offsets = displayLuts->offsets; + auto& lutProperties = displayLuts->lutProperties; + std::vector buffers; + int fullLength = offsets[lutProperties.size() - 1]; + if (lutProperties[lutProperties.size() - 1].dimension == 1) { + fullLength += lutProperties[lutProperties.size() - 1].size; + } else { + fullLength += (lutProperties[lutProperties.size() - 1].size * + lutProperties[lutProperties.size() - 1].size * + lutProperties[lutProperties.size() - 1].size * 3); + } + size_t bufferSize = fullLength * sizeof(float); + + // decode the shared memory of luts + float* ptr = + (float*)mmap(NULL, bufferSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd.get(), 0); + if (ptr == MAP_FAILED) { + LOG_ALWAYS_FATAL("mmap failed"); + } + buffers = std::vector(ptr, ptr + fullLength); + munmap(ptr, bufferSize); + + for (size_t i = 0; i < offsets.size(); i++) { + int bufferSizePerLut = (i == offsets.size() - 1) ? buffers.size() - offsets[i] + : offsets[i + 1] - offsets[i]; + // divide by 3 for 3d Lut because of 3 (RGB) channels + if (static_cast(lutProperties[i].dimension) == + LutProperties::Dimension::THREE_D) { + bufferSizePerLut /= 3; + } + input = generateLutShader(input, buffers, offsets[i], bufferSizePerLut, + lutProperties[i].dimension, lutProperties[i].size, + lutProperties[i].samplingKey); + } + + // re-gamma + baseImage = input->isAImage((SkMatrix*)nullptr, (SkTileMode*)nullptr); + if (baseImage) { + sk_sp baseColorSpace = + baseImage->colorSpace() ? baseImage->refColorSpace() : SkColorSpace::MakeSRGB(); + sk_sp gainmapMathColorSpace = baseColorSpace->makeLinearGamma(); + auto colorXformGainmapToDst = + SkColorFilterPriv::MakeColorSpaceXform(gainmapMathColorSpace, baseColorSpace); + input = input->makeWithColorFilter(colorXformGainmapToDst); + } + } + return input; +} + +} // namespace skia +} // namespace renderengine +} // namespace android \ No newline at end of file diff --git a/libs/renderengine/skia/filters/LutShader.h b/libs/renderengine/skia/filters/LutShader.h new file mode 100644 index 0000000000..c157904b63 --- /dev/null +++ b/libs/renderengine/skia/filters/LutShader.h @@ -0,0 +1,44 @@ +/* + * Copyright 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *- + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +#include +#include +#include + +#include +#include + +namespace android { +namespace renderengine { +namespace skia { + +class LutShader { +public: + sk_sp lutShader(sk_sp& input, + std::shared_ptr displayLuts); + +private: + sk_sp generateLutShader(sk_sp input, const std::vector& buffers, + const int32_t offset, const int32_t length, + const int32_t dimension, const int32_t size, + const int32_t samplingKey); + std::unique_ptr mBuilder; +}; + +} // namespace skia +} // namespace renderengine +} // namespace android diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h index 0c7e4dd071..bfa387dbfb 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h @@ -101,7 +101,7 @@ private: aidl::android::hardware::graphics::composer3::Composition from, aidl::android::hardware::graphics::composer3::Composition to) const; bool isClientCompositionForced(bool isPeekingThrough) const; - void updateLuts(std::shared_ptr luts, + void updateLuts(const LayerFECompositionState&, const std::optional>>& properties); }; diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp index 934909d066..c062df37e8 100644 --- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp +++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp @@ -286,8 +286,13 @@ uint32_t OutputLayer::calculateOutputRelativeBufferTransform( } void OutputLayer::updateLuts( - std::shared_ptr layerFEStateLut, + const LayerFECompositionState& layerFEState, const std::optional>>& properties) { + auto& luts = layerFEState.luts; + if (!luts) { + return; + } + auto& state = editState(); if (!properties) { @@ -303,7 +308,7 @@ void OutputLayer::updateLuts( } } - for (const auto& inputLut : layerFEStateLut->lutProperties) { + for (const auto& inputLut : luts->lutProperties) { bool foundInHwcLuts = false; for (const auto& hwcLut : hwcLutProperties) { if (static_cast(hwcLut.dimension) == @@ -316,7 +321,7 @@ void OutputLayer::updateLuts( break; } } - // if any lut properties of layerFEStateLut can not be found in hwcLutProperties, + // if any lut properties of luts can not be found in hwcLutProperties, // GPU composition instead if (!foundInHwcLuts) { state.forceClientComposition = true; @@ -409,10 +414,7 @@ void OutputLayer::updateCompositionState( state.whitePointNits = layerBrightnessNits; } - const auto& layerFEStateLut = layerFEState->luts; - if (layerFEStateLut) { - updateLuts(layerFEStateLut, properties); - } + updateLuts(*layerFEState, properties); // These are evaluated every frame as they can potentially change at any // time. diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp index 713a5c509e..ee9302b937 100644 --- a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp +++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp @@ -163,7 +163,7 @@ void RequestedLayerState::merge(const ResolvedComposerState& resolvedComposerSta uint64_t clientChanges = what | layer_state_t::diff(clientState); layer_state_t::merge(clientState); what = clientChanges; - LLOGV(layerId, "requested=%" PRIu64 "flags=%" PRIu64, clientState.what, clientChanges); + LLOGV(layerId, "requested=%" PRIu64 " flags=%" PRIu64 " ", clientState.what, clientChanges); if (clientState.what & layer_state_t::eFlagsChanged) { if ((oldFlags ^ flags) & @@ -633,7 +633,7 @@ bool RequestedLayerState::isSimpleBufferUpdate(const layer_state_t& s) const { layer_state_t::eEdgeExtensionChanged | layer_state_t::eBufferCropChanged | layer_state_t::eDestinationFrameChanged | layer_state_t::eDimmingEnabledChanged | layer_state_t::eExtendedRangeBrightnessChanged | - layer_state_t::eDesiredHdrHeadroomChanged | + layer_state_t::eDesiredHdrHeadroomChanged | layer_state_t::eLutsChanged | (FlagManager::getInstance().latch_unsignaled_with_auto_refresh_changed() ? layer_state_t::eFlagsChanged : 0); -- cgit v1.2.3-59-g8ed1b From f5fdff8d956bf61afd767c829810fa93b9909b4a Mon Sep 17 00:00:00 2001 From: Brian Lindahl Date: Fri, 1 Nov 2024 09:28:47 -0600 Subject: Notify listeners about active picture profiles Bug: 337330263 Test: atest ActivePictureUpdaterTest Test: atest SurfaceControlPictureProfileTest Flag: com.android.graphics.libgui.flags.apply_picture_profiles Change-Id: If08b79faf3d3c4c07248ecd7385a75cfe5357726 --- libs/gui/SurfaceComposerClient.cpp | 7 + libs/gui/aidl/android/gui/ActivePicture.aidl | 32 ++ .../aidl/android/gui/IActivePictureListener.aidl | 30 ++ libs/gui/aidl/android/gui/ISurfaceComposer.aidl | 7 + libs/gui/include/gui/SurfaceComposerClient.h | 2 + libs/gui/tests/Surface_test.cpp | 5 + services/surfaceflinger/ActivePictureUpdater.cpp | 66 ++++ services/surfaceflinger/ActivePictureUpdater.h | 47 +++ services/surfaceflinger/Android.bp | 1 + .../include/compositionengine/LayerFE.h | 3 + .../include/compositionengine/mock/LayerFE.h | 1 + .../CompositionEngine/src/Output.cpp | 2 + .../CompositionEngine/src/OutputLayer.cpp | 2 +- .../CompositionEngine/tests/OutputTest.cpp | 10 + services/surfaceflinger/LayerFE.cpp | 11 +- services/surfaceflinger/LayerFE.h | 10 +- services/surfaceflinger/SurfaceFlinger.cpp | 81 ++++- services/surfaceflinger/SurfaceFlinger.h | 14 + .../tests/unittests/ActivePictureUpdaterTest.cpp | 336 +++++++++++++++++++++ .../tests/unittests/BackgroundExecutorTest.cpp | 16 + .../tests/unittests/mock/MockLayer.h | 9 +- 21 files changed, 670 insertions(+), 22 deletions(-) create mode 100644 libs/gui/aidl/android/gui/ActivePicture.aidl create mode 100644 libs/gui/aidl/android/gui/IActivePictureListener.aidl create mode 100644 services/surfaceflinger/ActivePictureUpdater.cpp create mode 100644 services/surfaceflinger/ActivePictureUpdater.h create mode 100644 services/surfaceflinger/tests/unittests/ActivePictureUpdaterTest.cpp (limited to 'libs/gui/SurfaceComposerClient.cpp') diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 61aabaa7f6..1f7d16fccb 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -3280,6 +3280,13 @@ status_t SurfaceComposerClient::removeHdrLayerInfoListener( return statusTFromBinderStatus(status); } +status_t SurfaceComposerClient::setActivePictureListener( + const sp& listener) { + binder::Status status = + ComposerServiceAIDL::getComposerService()->setActivePictureListener(listener); + return statusTFromBinderStatus(status); +} + status_t SurfaceComposerClient::notifyPowerBoost(int32_t boostId) { binder::Status status = ComposerServiceAIDL::getComposerService()->notifyPowerBoost(boostId); return statusTFromBinderStatus(status); diff --git a/libs/gui/aidl/android/gui/ActivePicture.aidl b/libs/gui/aidl/android/gui/ActivePicture.aidl new file mode 100644 index 0000000000..9b83be16ca --- /dev/null +++ b/libs/gui/aidl/android/gui/ActivePicture.aidl @@ -0,0 +1,32 @@ +/* + * Copyright 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.gui; + +/** + * Visible content that is using picture processing. + * @hide + */ +parcelable ActivePicture { + /** The layer ID that is using picture processing. */ + int layerId; + + /** UID that owns layer using picture processing. */ + int ownerUid; + + /** ID of the picture profile that was used to configure the picture processing. */ + long pictureProfileId; +} diff --git a/libs/gui/aidl/android/gui/IActivePictureListener.aidl b/libs/gui/aidl/android/gui/IActivePictureListener.aidl new file mode 100644 index 0000000000..ad310bbd66 --- /dev/null +++ b/libs/gui/aidl/android/gui/IActivePictureListener.aidl @@ -0,0 +1,30 @@ +/* + * Copyright 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.gui; + +import android.gui.ActivePicture; + +/** + * Receive callbacks whenever the visible content using picture profiles changes. + * @hide + */ +interface IActivePictureListener { + /** + * Callback reporting the visible content on the screen using picture profiles. + */ + oneway void onActivePicturesChanged(in ActivePicture[] activePictures); +} diff --git a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl index ac14138e8c..c8bf0ef444 100644 --- a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl +++ b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl @@ -33,6 +33,7 @@ import android.gui.FrameEvent; import android.gui.FrameStats; import android.gui.HdrConversionCapability; import android.gui.HdrConversionStrategy; +import android.gui.IActivePictureListener; import android.gui.IDisplayEventConnection; import android.gui.IFpsListener; import android.gui.IHdrLayerInfoListener; @@ -599,4 +600,10 @@ interface ISurfaceComposer { * past the provided VSync. */ oneway void removeJankListener(int layerId, IJankListener listener, long afterVsync); + + /** + * Sets the listener used to monitor visible content that is being processed with picture + * profiles. + */ + oneway void setActivePictureListener(IActivePictureListener listener); } diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 0d7f8c2824..ec62ec3dfb 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -298,6 +298,8 @@ public: static status_t removeHdrLayerInfoListener(const sp& displayToken, const sp& listener); + static status_t setActivePictureListener(const sp& listener); + /* * Sends a power boost to the composer. This function is asynchronous. * diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index c74186682e..38c7f2b70a 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -1015,6 +1016,10 @@ public: return binder::Status::ok(); } + binder::Status setActivePictureListener(const sp&) { + return binder::Status::ok(); + } + protected: IBinder* onAsBinder() override { return nullptr; } diff --git a/services/surfaceflinger/ActivePictureUpdater.cpp b/services/surfaceflinger/ActivePictureUpdater.cpp new file mode 100644 index 0000000000..210e948a49 --- /dev/null +++ b/services/surfaceflinger/ActivePictureUpdater.cpp @@ -0,0 +1,66 @@ +/* + * Copyright 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ActivePictureUpdater.h" + +#include + +#include "Layer.h" +#include "LayerFE.h" + +namespace android { + +void ActivePictureUpdater::onLayerComposed(const Layer& layer, const LayerFE& layerFE, + const CompositionResult& result) { + if (result.wasPictureProfileCommitted) { + gui::ActivePicture picture; + picture.layerId = int32_t(layer.sequence); + picture.ownerUid = int32_t(layer.getOwnerUid()); + // TODO(b/337330263): Why does LayerFE coming from SF have a null composition state? + if (layerFE.getCompositionState()) { + picture.pictureProfileId = layerFE.getCompositionState()->pictureProfileHandle.getId(); + } else { + picture.pictureProfileId = result.pictureProfileHandle.getId(); + } + mNewActivePictures.push_back(picture); + } +} + +bool ActivePictureUpdater::updateAndHasChanged() { + bool hasChanged = true; + if (mNewActivePictures.size() == mOldActivePictures.size()) { + auto compare = [](const gui::ActivePicture& lhs, const gui::ActivePicture& rhs) -> int { + if (lhs.layerId == rhs.layerId) { + return lhs.pictureProfileId < rhs.pictureProfileId; + } + return lhs.layerId < rhs.layerId; + }; + std::sort(mNewActivePictures.begin(), mNewActivePictures.end(), compare); + if (std::equal(mNewActivePictures.begin(), mNewActivePictures.end(), + mOldActivePictures.begin())) { + hasChanged = false; + } + } + std::swap(mOldActivePictures, mNewActivePictures); + mNewActivePictures.resize(0); + return hasChanged; +} + +const std::vector& ActivePictureUpdater::getActivePictures() const { + return mOldActivePictures; +} + +} // namespace android diff --git a/services/surfaceflinger/ActivePictureUpdater.h b/services/surfaceflinger/ActivePictureUpdater.h new file mode 100644 index 0000000000..20779bb0ff --- /dev/null +++ b/services/surfaceflinger/ActivePictureUpdater.h @@ -0,0 +1,47 @@ +/* + * Copyright 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#include + +namespace android { + +class Layer; +class LayerFE; +struct CompositionResult; + +// Keeps track of active pictures - layers that are undergoing picture processing. +class ActivePictureUpdater { +public: + // Called for each visible layer when SurfaceFlinger finishes composing. + void onLayerComposed(const Layer& layer, const LayerFE& layerFE, + const CompositionResult& result); + + // Update internals and return whether the set of active pictures have changed. + bool updateAndHasChanged(); + + // The current set of active pictures. + const std::vector& getActivePictures() const; + +private: + std::vector mOldActivePictures; + std::vector mNewActivePictures; +}; + +} // namespace android diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index 8a667aef72..3f3d2c6cc6 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -199,6 +199,7 @@ filegroup { name: "libsurfaceflinger_sources", srcs: [ ":libsurfaceflinger_backend_sources", + "ActivePictureUpdater.cpp", "BackgroundExecutor.cpp", "Client.cpp", "ClientCache.cpp", diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h index a5e9dded8b..cda4edc216 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h @@ -161,6 +161,9 @@ public: // Checks if the buffer's release fence has been set virtual LayerFE::ReleaseFencePromiseStatus getReleaseFencePromiseStatus() = 0; + // Indicates that the picture profile request was applied to this layer. + virtual void onPictureProfileCommitted() = 0; + // Gets some kind of identifier for the layer for debug purposes. virtual const char* getDebugName() const = 0; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h index c7ff704491..272fa3eef7 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h @@ -58,6 +58,7 @@ public: MOCK_CONST_METHOD0(hasRoundedCorners, bool()); MOCK_CONST_METHOD0(getMetadata, gui::LayerMetadata*()); MOCK_CONST_METHOD0(getRelativeMetadata, gui::LayerMetadata*()); + MOCK_METHOD0(onPictureProfileCommitted, void()); }; } // namespace android::compositionengine::mock diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index ee813bf340..f9ed92d1ee 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -830,11 +830,13 @@ void Output::commitPictureProfilesToCompositionState() { for (int i = 0; i < getMaxLayerPictureProfiles() && !layersWithProfiles.empty(); layersWithProfiles.pop(), ++i) { layersWithProfiles.top()->commitPictureProfileToCompositionState(); + layersWithProfiles.top()->getLayerFE().onPictureProfileCommitted(); } // No layer-specific picture processing, so apply the highest priority picture profile to // the entire display. } else if (!layersWithProfiles.empty()) { editState().pictureProfileHandle = layersWithProfiles.top()->getPictureProfileHandle(); + layersWithProfiles.top()->getLayerFE().onPictureProfileCommitted(); } } diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp index f6d9a1ae6c..65ded8b4c1 100644 --- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp +++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp @@ -432,7 +432,7 @@ void OutputLayer::commitPictureProfileToCompositionState() { } const auto* layerState = getLayerFE().getCompositionState(); if (layerState) { - editState().pictureProfileHandle = getLayerFE().getCompositionState()->pictureProfileHandle; + editState().pictureProfileHandle = layerState->pictureProfileHandle; } } diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp index 99e68eb71a..442b603ca0 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp @@ -5117,6 +5117,11 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, assignsDisplayProfileBasedOnLay // Sets display picture profile to the highest priority layer's profile EXPECT_CALL(mHwComposer, setDisplayPictureProfileHandle(_, Eq(profileForLayer2))); + // Marks only the highest priority layer as committed + EXPECT_CALL(*layer1.layerFE, onPictureProfileCommitted).Times(0); + EXPECT_CALL(*layer2.layerFE, onPictureProfileCommitted); + EXPECT_CALL(*layer3.layerFE, onPictureProfileCommitted).Times(0); + mOutput->editState().isEnabled = true; CompositionRefreshArgs args; args.updatingGeometryThisFrame = false; @@ -5172,6 +5177,11 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, assignsLayerProfileBasedOnLayer EXPECT_CALL(*layer2.outputLayer, commitPictureProfileToCompositionState); EXPECT_CALL(*layer3.outputLayer, commitPictureProfileToCompositionState); + // Marks only the highest priority layers as committed + EXPECT_CALL(*layer1.layerFE, onPictureProfileCommitted).Times(0); + EXPECT_CALL(*layer2.layerFE, onPictureProfileCommitted); + EXPECT_CALL(*layer3.layerFE, onPictureProfileCommitted); + // No display picture profile is sent EXPECT_CALL(mHwComposer, setDisplayPictureProfileHandle).Times(0); diff --git a/services/surfaceflinger/LayerFE.cpp b/services/surfaceflinger/LayerFE.cpp index 231b40b0ac..fea7671af2 100644 --- a/services/surfaceflinger/LayerFE.cpp +++ b/services/surfaceflinger/LayerFE.cpp @@ -342,8 +342,15 @@ void LayerFE::prepareShadowClientComposition(LayerFE::LayerSettings& caster, caster.shadow = state; } -CompositionResult&& LayerFE::stealCompositionResult() { - return std::move(mCompositionResult); +void LayerFE::onPictureProfileCommitted() { + mCompositionResult.wasPictureProfileCommitted = true; + mCompositionResult.pictureProfileHandle = mSnapshot->pictureProfileHandle; +} + +CompositionResult LayerFE::stealCompositionResult() { + CompositionResult result; + std::swap(mCompositionResult, result); + return result; } const char* LayerFE::getDebugName() const { diff --git a/services/surfaceflinger/LayerFE.h b/services/surfaceflinger/LayerFE.h index 5081e102b8..9483aebafa 100644 --- a/services/surfaceflinger/LayerFE.h +++ b/services/surfaceflinger/LayerFE.h @@ -18,6 +18,9 @@ #include #include +#include +#include + #include "FrontEnd/LayerSnapshot.h" #include "compositionengine/LayerFE.h" #include "compositionengine/LayerFECompositionState.h" @@ -29,6 +32,10 @@ namespace android { struct CompositionResult { sp lastClientCompositionFence = nullptr; + bool wasPictureProfileCommitted = false; + // TODO(b/337330263): Why does LayerFE coming from SF have a null composition state? + // It would be better not to duplicate this information + PictureProfileHandle pictureProfileHandle = PictureProfileHandle::NONE; }; class LayerFE : public virtual RefBase, public virtual compositionengine::LayerFE { @@ -47,10 +54,11 @@ public: const gui::LayerMetadata* getRelativeMetadata() const override; std::optional prepareClientComposition( compositionengine::LayerFE::ClientCompositionTargetSettings&) const; - CompositionResult&& stealCompositionResult(); + CompositionResult stealCompositionResult(); ftl::Future createReleaseFenceFuture() override; void setReleaseFence(const FenceResult& releaseFence) override; LayerFE::ReleaseFencePromiseStatus getReleaseFencePromiseStatus() override; + void onPictureProfileCommitted() override; std::unique_ptr mSnapshot; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 1f35173f65..dfaf8b6c04 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -126,6 +126,7 @@ #include #include #include +#include "ActivePictureUpdater.h" #include "BackgroundExecutor.h" #include "Client.h" #include "ClientCache.h" @@ -372,6 +373,7 @@ const String16 sAccessSurfaceFlinger("android.permission.ACCESS_SURFACE_FLINGER" const String16 sRotateSurfaceFlinger("android.permission.ROTATE_SURFACE_FLINGER"); const String16 sReadFramebuffer("android.permission.READ_FRAME_BUFFER"); const String16 sControlDisplayBrightness("android.permission.CONTROL_DISPLAY_BRIGHTNESS"); +const String16 sObservePictureProfiles("android.permission.OBSERVE_PICTURE_PROFILES"); const String16 sDump("android.permission.DUMP"); const String16 sCaptureBlackoutContent("android.permission.CAPTURE_BLACKOUT_CONTENT"); const String16 sInternalSystemWindow("android.permission.INTERNAL_SYSTEM_WINDOW"); @@ -2851,6 +2853,9 @@ CompositeResultsPerDisplay SurfaceFlinger::composite( if (compositionResult.lastClientCompositionFence) { layer->setWasClientComposed(compositionResult.lastClientCompositionFence); } + if (com_android_graphics_libgui_flags_apply_picture_profiles()) { + mActivePictureUpdater.onLayerComposed(*layer, *layerFE, compositionResult); + } } SFTRACE_NAME("postComposition"); @@ -3146,9 +3151,23 @@ void SurfaceFlinger::onCompositionPresented(PhysicalDisplayId pacesetterId, layer->releasePendingBuffer(presentTime.ns()); } + for (const auto& layerEvent : mLayerEvents) { + auto result = + stats::stats_write(stats::SURFACE_CONTROL_EVENT, + static_cast(layerEvent.uid), + static_cast(layerEvent.timeSinceLastEvent.count()), + static_cast(layerEvent.dataspace)); + if (result < 0) { + ALOGW("Failed to report layer event with error: %d", result); + } + } + mLayerEvents.clear(); + std::vector, sp>> hdrInfoListeners; - bool haveNewListeners = false; + bool haveNewHdrInfoListeners = false; + sp activePictureListener; + bool haveNewActivePictureListener = false; { Mutex::Autolock lock(mStateLock); if (mFpsReporter) { @@ -3158,6 +3177,7 @@ void SurfaceFlinger::onCompositionPresented(PhysicalDisplayId pacesetterId, if (mTunnelModeEnabledReporter) { mTunnelModeEnabledReporter->updateTunnelModeStatus(); } + hdrInfoListeners.reserve(mHdrLayerInfoListeners.size()); for (const auto& [displayId, reporter] : mHdrLayerInfoListeners) { if (reporter && reporter->hasListeners()) { @@ -3166,24 +3186,15 @@ void SurfaceFlinger::onCompositionPresented(PhysicalDisplayId pacesetterId, } } } - haveNewListeners = mAddingHDRLayerInfoListener; // grab this with state lock + haveNewHdrInfoListeners = mAddingHDRLayerInfoListener; // grab this with state lock mAddingHDRLayerInfoListener = false; - } - for (const auto& layerEvent : mLayerEvents) { - auto result = - stats::stats_write(stats::SURFACE_CONTROL_EVENT, - static_cast(layerEvent.uid), - static_cast(layerEvent.timeSinceLastEvent.count()), - static_cast(layerEvent.dataspace)); - if (result < 0) { - ALOGW("Failed to report layer event with error: %d", result); - } + activePictureListener = mActivePictureListener; + haveNewActivePictureListener = mHaveNewActivePictureListener; + mHaveNewActivePictureListener = false; } - mLayerEvents.clear(); - - if (haveNewListeners || mHdrLayerInfoChanged) { + if (haveNewHdrInfoListeners || mHdrLayerInfoChanged) { for (auto& [compositionDisplay, listener] : hdrInfoListeners) { HdrLayerInfoReporter::HdrLayerInfo info; int32_t maxArea = 0; @@ -3233,9 +3244,19 @@ void SurfaceFlinger::onCompositionPresented(PhysicalDisplayId pacesetterId, listener->dispatchHdrLayerInfo(info); } } - mHdrLayerInfoChanged = false; + if (com_android_graphics_libgui_flags_apply_picture_profiles()) { + // Track, update and notify changes to active pictures - layers that are undergoing picture + // processing + if (mActivePictureUpdater.updateAndHasChanged() || haveNewActivePictureListener) { + if (activePictureListener) { + activePictureListener->onActivePicturesChanged( + mActivePictureUpdater.getActivePictures()); + } + } + } + mTransactionCallbackInvoker.sendCallbacks(false /* onCommitOnly */); mTransactionCallbackInvoker.clearCompletedTransactions(); @@ -8073,6 +8094,14 @@ void SurfaceFlinger::updateHdcpLevels(hal::HWDisplayId hwcDisplayId, int32_t con })); } +void SurfaceFlinger::setActivePictureListener(const sp& listener) { + if (com_android_graphics_libgui_flags_apply_picture_profiles()) { + Mutex::Autolock lock(mStateLock); + mActivePictureListener = listener; + mHaveNewActivePictureListener = listener != nullptr; + } +} + std::shared_ptr SurfaceFlinger::getExternalTextureFromBufferData( BufferData& bufferData, const char* layerName, uint64_t transactionId) { if (bufferData.buffer && @@ -9008,6 +9037,15 @@ binder::Status SurfaceComposerAIDL::removeHdrLayerInfoListener( return binderStatusFromStatusT(status); } +binder::Status SurfaceComposerAIDL::setActivePictureListener( + const sp& listener) { + status_t status = checkObservePictureProfilesPermission(); + if (status == OK) { + mFlinger->setActivePictureListener(listener); + } + return binderStatusFromStatusT(status); +} + binder::Status SurfaceComposerAIDL::notifyPowerBoost(int boostId) { status_t status = checkAccessPermission(); if (status == OK) { @@ -9263,6 +9301,17 @@ status_t SurfaceComposerAIDL::checkReadFrameBufferPermission() { return OK; } +status_t SurfaceComposerAIDL::checkObservePictureProfilesPermission() { + IPCThreadState* ipc = IPCThreadState::self(); + const int pid = ipc->getCallingPid(); + const int uid = ipc->getCallingUid(); + if (!PermissionCache::checkPermission(sObservePictureProfiles, pid, uid)) { + ALOGE("Permission Denial: can't manage picture profiles pid=%d, uid=%d", pid, uid); + return PERMISSION_DENIED; + } + return OK; +} + void SurfaceFlinger::forceFutureUpdate(int delayInMs) { static_cast(mScheduler->scheduleDelayed([&]() { scheduleRepaint(); }, ms2ns(delayInMs))); } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 7e9d5b881f..cbe2739664 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -24,9 +24,11 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -67,6 +69,8 @@ #include #include +#include "ActivePictureUpdater.h" +#include "BackgroundExecutor.h" #include "Display/DisplayModeController.h" #include "Display/PhysicalDisplay.h" #include "DisplayDevice.h" @@ -93,6 +97,7 @@ #include "TransactionState.h" #include "Utils/OnceFuture.h" +#include #include #include #include @@ -660,6 +665,8 @@ private: void updateHdcpLevels(hal::HWDisplayId hwcDisplayId, int32_t connectedLevel, int32_t maxLevel); + void setActivePictureListener(const sp& listener); + // IBinder::DeathRecipient overrides: void binderDied(const wp& who) override; @@ -1377,6 +1384,10 @@ private: std::unordered_map> mHdrLayerInfoListeners GUARDED_BY(mStateLock); + sp mActivePictureListener GUARDED_BY(mStateLock); + bool mHaveNewActivePictureListener GUARDED_BY(mStateLock); + ActivePictureUpdater mActivePictureUpdater GUARDED_BY(kMainThreadContext); + std::atomic mActiveDisplayTransformHint; // Must only be accessed on the main thread. @@ -1610,12 +1621,15 @@ public: binder::Status flushJankData(int32_t layerId) override; binder::Status removeJankListener(int32_t layerId, const sp& listener, int64_t afterVsync) override; + binder::Status setActivePictureListener(const sp& listener); + binder::Status clearActivePictureListener(); private: static const constexpr bool kUsePermissionCache = true; status_t checkAccessPermission(bool usePermissionCache = kUsePermissionCache); status_t checkControlDisplayBrightnessPermission(); status_t checkReadFrameBufferPermission(); + status_t checkObservePictureProfilesPermission(); static void getDynamicDisplayInfoInternal(ui::DynamicDisplayInfo& info, gui::DynamicDisplayInfo*& outInfo); diff --git a/services/surfaceflinger/tests/unittests/ActivePictureUpdaterTest.cpp b/services/surfaceflinger/tests/unittests/ActivePictureUpdaterTest.cpp new file mode 100644 index 0000000000..b926d2f4da --- /dev/null +++ b/services/surfaceflinger/tests/unittests/ActivePictureUpdaterTest.cpp @@ -0,0 +1,336 @@ +/* + * Copyright 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "ActivePictureUpdater.h" +#include "LayerFE.h" +#include "TestableSurfaceFlinger.h" + +namespace android { + +using android::compositionengine::LayerFECompositionState; +using android::gui::ActivePicture; +using android::gui::IActivePictureListener; +using android::mock::MockLayer; +using surfaceflinger::frontend::LayerSnapshot; +using testing::_; +using testing::NiceMock; +using testing::Return; + +class TestableLayerFE : public LayerFE { +public: + TestableLayerFE() : LayerFE("TestableLayerFE"), snapshot(*(new LayerSnapshot)) { + mSnapshot = std::unique_ptr(&snapshot); + } + + LayerSnapshot& snapshot; +}; + +class ActivePictureUpdaterTest : public testing::Test { +protected: + SurfaceFlinger* flinger() { + if (!mFlingerSetup) { + mFlinger.setupMockScheduler(); + mFlinger.setupComposer(std::make_unique()); + mFlinger.setupRenderEngine(std::make_unique()); + mFlingerSetup = true; + } + return mFlinger.flinger(); + } + +private: + TestableSurfaceFlinger mFlinger; + bool mFlingerSetup = false; +}; + +// Hack to workaround initializer lists not working for parcelables because parcelables inherit from +// Parcelable, which has a virtual destructor. +auto UnorderedElementsAre(std::initializer_list> tuples) { + std::vector activePictures; + for (auto tuple : tuples) { + ActivePicture ap; + ap.layerId = std::get<0>(tuple); + ap.ownerUid = std::get<1>(tuple); + ap.pictureProfileId = std::get<2>(tuple); + activePictures.push_back(ap); + } + return testing::UnorderedElementsAreArray(activePictures); +} + +// Parcelables don't define this for matchers, which is unfortunate +void PrintTo(const ActivePicture& activePicture, std::ostream* os) { + *os << activePicture.toString(); +} + +TEST_F(ActivePictureUpdaterTest, notCalledWithNoProfile) { + sp> layer = sp>::make(flinger(), 100); + TestableLayerFE layerFE; + EXPECT_CALL(*layer, getOwnerUid()).WillRepeatedly(Return(uid_t(10))); + + ActivePictureUpdater updater; + { + layerFE.snapshot.pictureProfileHandle = PictureProfileHandle::NONE; + updater.onLayerComposed(*layer, layerFE, layerFE.stealCompositionResult()); + + ASSERT_FALSE(updater.updateAndHasChanged()); + } +} + +TEST_F(ActivePictureUpdaterTest, calledWhenLayerStartsUsingProfile) { + sp> layer = sp>::make(flinger(), 100); + TestableLayerFE layerFE; + EXPECT_CALL(*layer, getOwnerUid()).WillRepeatedly(Return(uid_t(10))); + + ActivePictureUpdater updater; + { + layerFE.snapshot.pictureProfileHandle = PictureProfileHandle::NONE; + updater.onLayerComposed(*layer, layerFE, layerFE.stealCompositionResult()); + + ASSERT_FALSE(updater.updateAndHasChanged()); + } + { + layerFE.snapshot.pictureProfileHandle = PictureProfileHandle(1); + layerFE.onPictureProfileCommitted(); + updater.onLayerComposed(*layer, layerFE, layerFE.stealCompositionResult()); + + ASSERT_TRUE(updater.updateAndHasChanged()); + EXPECT_THAT(updater.getActivePictures(), UnorderedElementsAre({{100, 10, 1}})); + } +} + +TEST_F(ActivePictureUpdaterTest, notCalledWhenLayerContinuesUsingProfile) { + sp> layer = sp>::make(flinger(), 100); + TestableLayerFE layerFE; + EXPECT_CALL(*layer, getOwnerUid()).WillRepeatedly(Return(uid_t(10))); + + ActivePictureUpdater updater; + { + layerFE.snapshot.pictureProfileHandle = PictureProfileHandle(1); + layerFE.onPictureProfileCommitted(); + updater.onLayerComposed(*layer, layerFE, layerFE.stealCompositionResult()); + + ASSERT_TRUE(updater.updateAndHasChanged()); + EXPECT_THAT(updater.getActivePictures(), UnorderedElementsAre({{100, 10, 1}})); + } + { + layerFE.snapshot.pictureProfileHandle = PictureProfileHandle(1); + layerFE.onPictureProfileCommitted(); + updater.onLayerComposed(*layer, layerFE, layerFE.stealCompositionResult()); + + ASSERT_FALSE(updater.updateAndHasChanged()); + } +} + +TEST_F(ActivePictureUpdaterTest, calledWhenLayerStopsUsingProfile) { + sp> layer = sp>::make(flinger(), 100); + TestableLayerFE layerFE; + EXPECT_CALL(*layer, getOwnerUid()).WillRepeatedly(Return(uid_t(10))); + + ActivePictureUpdater updater; + { + layerFE.snapshot.pictureProfileHandle = PictureProfileHandle(1); + layerFE.onPictureProfileCommitted(); + updater.onLayerComposed(*layer, layerFE, layerFE.stealCompositionResult()); + + ASSERT_TRUE(updater.updateAndHasChanged()); + EXPECT_THAT(updater.getActivePictures(), UnorderedElementsAre({{100, 10, 1}})); + } + { + layerFE.snapshot.pictureProfileHandle = PictureProfileHandle::NONE; + updater.onLayerComposed(*layer, layerFE, layerFE.stealCompositionResult()); + + ASSERT_TRUE(updater.updateAndHasChanged()); + EXPECT_THAT(updater.getActivePictures(), UnorderedElementsAre({})); + } +} + +TEST_F(ActivePictureUpdaterTest, calledWhenLayerChangesProfile) { + sp> layer = sp>::make(flinger(), 100); + TestableLayerFE layerFE; + EXPECT_CALL(*layer, getOwnerUid()).WillRepeatedly(Return(uid_t(10))); + + ActivePictureUpdater updater; + { + layerFE.snapshot.pictureProfileHandle = PictureProfileHandle(1); + layerFE.onPictureProfileCommitted(); + updater.onLayerComposed(*layer, layerFE, layerFE.stealCompositionResult()); + + ASSERT_TRUE(updater.updateAndHasChanged()); + EXPECT_THAT(updater.getActivePictures(), UnorderedElementsAre({{100, 10, 1}})); + } + { + layerFE.snapshot.pictureProfileHandle = PictureProfileHandle(2); + layerFE.onPictureProfileCommitted(); + updater.onLayerComposed(*layer, layerFE, layerFE.stealCompositionResult()); + + ASSERT_TRUE(updater.updateAndHasChanged()); + EXPECT_THAT(updater.getActivePictures(), UnorderedElementsAre({{100, 10, 2}})); + } +} + +TEST_F(ActivePictureUpdaterTest, notCalledWhenUncommittedLayerChangesProfile) { + sp> layer1 = sp>::make(flinger(), 100); + TestableLayerFE layerFE1; + EXPECT_CALL(*layer1, getOwnerUid()).WillRepeatedly(Return(uid_t(10))); + + sp> layer2 = sp>::make(flinger(), 200); + TestableLayerFE layerFE2; + EXPECT_CALL(*layer2, getOwnerUid()).WillRepeatedly(Return(uid_t(20))); + + ActivePictureUpdater updater; + { + layerFE1.snapshot.pictureProfileHandle = PictureProfileHandle(1); + layerFE1.onPictureProfileCommitted(); + updater.onLayerComposed(*layer1, layerFE1, layerFE1.stealCompositionResult()); + + layerFE2.snapshot.pictureProfileHandle = PictureProfileHandle(1); + updater.onLayerComposed(*layer2, layerFE2, layerFE2.stealCompositionResult()); + + ASSERT_TRUE(updater.updateAndHasChanged()); + EXPECT_THAT(updater.getActivePictures(), UnorderedElementsAre({{100, 10, 1}})); + } + { + layerFE1.snapshot.pictureProfileHandle = PictureProfileHandle(1); + layerFE1.onPictureProfileCommitted(); + updater.onLayerComposed(*layer1, layerFE1, layerFE1.stealCompositionResult()); + + layerFE2.snapshot.pictureProfileHandle = PictureProfileHandle(2); + updater.onLayerComposed(*layer2, layerFE2, layerFE2.stealCompositionResult()); + + ASSERT_FALSE(updater.updateAndHasChanged()); + } +} + +TEST_F(ActivePictureUpdaterTest, calledWhenDifferentLayerUsesSameProfile) { + sp> layer1 = sp>::make(flinger(), 100); + TestableLayerFE layerFE1; + EXPECT_CALL(*layer1, getOwnerUid()).WillRepeatedly(Return(uid_t(10))); + + sp> layer2 = sp>::make(flinger(), 200); + TestableLayerFE layerFE2; + EXPECT_CALL(*layer2, getOwnerUid()).WillRepeatedly(Return(uid_t(20))); + + ActivePictureUpdater updater; + { + layerFE1.snapshot.pictureProfileHandle = PictureProfileHandle(1); + layerFE1.onPictureProfileCommitted(); + updater.onLayerComposed(*layer1, layerFE1, layerFE1.stealCompositionResult()); + + layerFE2.snapshot.pictureProfileHandle = PictureProfileHandle(2); + layerFE2.onPictureProfileCommitted(); + updater.onLayerComposed(*layer2, layerFE2, layerFE2.stealCompositionResult()); + + ASSERT_TRUE(updater.updateAndHasChanged()); + EXPECT_THAT(updater.getActivePictures(), + UnorderedElementsAre({{100, 10, 1}, {200, 20, 2}})); + } + { + layerFE1.snapshot.pictureProfileHandle = PictureProfileHandle(2); + layerFE1.onPictureProfileCommitted(); + updater.onLayerComposed(*layer1, layerFE1, layerFE1.stealCompositionResult()); + + layerFE2.snapshot.pictureProfileHandle = PictureProfileHandle(1); + layerFE2.onPictureProfileCommitted(); + updater.onLayerComposed(*layer2, layerFE2, layerFE2.stealCompositionResult()); + + ASSERT_TRUE(updater.updateAndHasChanged()); + EXPECT_THAT(updater.getActivePictures(), + UnorderedElementsAre({{100, 10, 2}, {200, 20, 1}})); + } +} + +TEST_F(ActivePictureUpdaterTest, calledWhenSameUidUsesSameProfile) { + sp> layer1 = sp>::make(flinger(), 100); + TestableLayerFE layerFE1; + EXPECT_CALL(*layer1, getOwnerUid()).WillRepeatedly(Return(uid_t(10))); + + sp> layer2 = sp>::make(flinger(), 200); + TestableLayerFE layerFE2; + EXPECT_CALL(*layer2, getOwnerUid()).WillRepeatedly(Return(uid_t(10))); + + ActivePictureUpdater updater; + { + layerFE1.snapshot.pictureProfileHandle = PictureProfileHandle(1); + layerFE1.onPictureProfileCommitted(); + updater.onLayerComposed(*layer1, layerFE1, layerFE1.stealCompositionResult()); + + layerFE2.snapshot.pictureProfileHandle = PictureProfileHandle(2); + layerFE2.onPictureProfileCommitted(); + updater.onLayerComposed(*layer2, layerFE2, layerFE2.stealCompositionResult()); + + ASSERT_TRUE(updater.updateAndHasChanged()); + EXPECT_THAT(updater.getActivePictures(), + UnorderedElementsAre({{100, 10, 1}, {200, 10, 2}})); + } + { + layerFE1.snapshot.pictureProfileHandle = PictureProfileHandle(2); + layerFE1.onPictureProfileCommitted(); + updater.onLayerComposed(*layer1, layerFE1, layerFE1.stealCompositionResult()); + + layerFE2.snapshot.pictureProfileHandle = PictureProfileHandle(1); + layerFE2.onPictureProfileCommitted(); + updater.onLayerComposed(*layer2, layerFE2, layerFE2.stealCompositionResult()); + + ASSERT_TRUE(updater.updateAndHasChanged()); + EXPECT_THAT(updater.getActivePictures(), + UnorderedElementsAre({{100, 10, 2}, {200, 10, 1}})); + } +} + +TEST_F(ActivePictureUpdaterTest, calledWhenNewLayerUsesSameProfile) { + sp> layer1 = sp>::make(flinger(), 100); + TestableLayerFE layerFE1; + EXPECT_CALL(*layer1, getOwnerUid()).WillRepeatedly(Return(uid_t(10))); + + ActivePictureUpdater updater; + { + layerFE1.snapshot.pictureProfileHandle = PictureProfileHandle(1); + layerFE1.onPictureProfileCommitted(); + updater.onLayerComposed(*layer1, layerFE1, layerFE1.stealCompositionResult()); + + ASSERT_TRUE(updater.updateAndHasChanged()); + EXPECT_THAT(updater.getActivePictures(), UnorderedElementsAre({{100, 10, 1}})); + } + + sp> layer2 = sp>::make(flinger(), 200); + TestableLayerFE layerFE2; + EXPECT_CALL(*layer2, getOwnerUid()).WillRepeatedly(Return(uid_t(10))); + + { + layerFE1.snapshot.pictureProfileHandle = PictureProfileHandle(1); + layerFE1.onPictureProfileCommitted(); + updater.onLayerComposed(*layer1, layerFE1, layerFE1.stealCompositionResult()); + + layerFE2.snapshot.pictureProfileHandle = PictureProfileHandle(1); + layerFE2.onPictureProfileCommitted(); + updater.onLayerComposed(*layer2, layerFE2, layerFE2.stealCompositionResult()); + + ASSERT_TRUE(updater.updateAndHasChanged()); + EXPECT_THAT(updater.getActivePictures(), + UnorderedElementsAre({{100, 10, 1}, {200, 10, 1}})); + } +} + +} // namespace android diff --git a/services/surfaceflinger/tests/unittests/BackgroundExecutorTest.cpp b/services/surfaceflinger/tests/unittests/BackgroundExecutorTest.cpp index 5413bae55c..72d1351eb4 100644 --- a/services/surfaceflinger/tests/unittests/BackgroundExecutorTest.cpp +++ b/services/surfaceflinger/tests/unittests/BackgroundExecutorTest.cpp @@ -1,3 +1,19 @@ +/* + * Copyright 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + #include #include diff --git a/services/surfaceflinger/tests/unittests/mock/MockLayer.h b/services/surfaceflinger/tests/unittests/mock/MockLayer.h index 45f86fa1a8..59f0966047 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockLayer.h +++ b/services/surfaceflinger/tests/unittests/mock/MockLayer.h @@ -19,6 +19,8 @@ #include #include +#include "Layer.h" + namespace android::mock { class MockLayer : public Layer { @@ -26,8 +28,11 @@ public: MockLayer(SurfaceFlinger* flinger, std::string name) : Layer(LayerCreationArgs(flinger, nullptr, std::move(name), 0, {})) {} - MockLayer(SurfaceFlinger* flinger, std::string name, std::optional uid) - : Layer(LayerCreationArgs(flinger, nullptr, std::move(name), 0, {}, uid)) {} + MockLayer(SurfaceFlinger* flinger, std::string name, std::optional id) + : Layer(LayerCreationArgs(flinger, nullptr, std::move(name), 0, {}, id)) {} + + MockLayer(SurfaceFlinger* flinger, std::optional id) + : Layer(LayerCreationArgs(flinger, nullptr, "TestLayer", 0, {}, id)) {} explicit MockLayer(SurfaceFlinger* flinger) : MockLayer(flinger, "TestLayer") {} -- cgit v1.2.3-59-g8ed1b From 5541f12784132f69629ad084cc4a8477bb40644e Mon Sep 17 00:00:00 2001 From: Brian Lindahl Date: Tue, 12 Nov 2024 13:22:34 -0700 Subject: Add API to retrieve max layer picture profiles Bug: 337330263 Test: atest SurfaceControlPictureProfileTest Flag: com.android.graphics.libgui.flags.apply_picture_profiles Change-Id: Idcfc3acd2e9eb89dd72baf0270d5d2a003d1f996 --- libs/gui/SurfaceComposerClient.cpp | 8 +++++++ libs/gui/aidl/android/gui/ISurfaceComposer.aidl | 5 +++++ libs/gui/include/gui/SurfaceComposerClient.h | 9 ++++++++ libs/gui/tests/Surface_test.cpp | 5 +++++ services/surfaceflinger/SurfaceFlinger.cpp | 28 +++++++++++++++++++++++++ services/surfaceflinger/SurfaceFlinger.h | 3 +++ 6 files changed, 58 insertions(+) (limited to 'libs/gui/SurfaceComposerClient.cpp') diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 1f7d16fccb..793377668c 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -3056,6 +3056,14 @@ void SurfaceComposerClient::setDisplayPowerMode(const sp& token, ComposerServiceAIDL::getComposerService()->setPowerMode(token, mode); } +status_t SurfaceComposerClient::getMaxLayerPictureProfiles(const sp& token, + int32_t* outMaxProfiles) { + binder::Status status = + ComposerServiceAIDL::getComposerService()->getMaxLayerPictureProfiles(token, + outMaxProfiles); + return statusTFromBinderStatus(status); +} + status_t SurfaceComposerClient::getCompositionPreference( ui::Dataspace* defaultDataspace, ui::PixelFormat* defaultPixelFormat, ui::Dataspace* wideColorGamutDataspace, ui::PixelFormat* wideColorGamutPixelFormat) { diff --git a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl index c8bf0ef444..8c19bbbba9 100644 --- a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl +++ b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl @@ -228,6 +228,11 @@ interface ISurfaceComposer { */ void setGameContentType(IBinder display, boolean on); + /** + * Gets the maximum number of picture profiles supported by the display. + */ + int getMaxLayerPictureProfiles(IBinder display); + /** * Capture the specified screen. This requires READ_FRAME_BUFFER * permission. This function will fail if there is a secure window on diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index ec62ec3dfb..0ce0c0a9c3 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -345,6 +345,15 @@ public: static bool flagEdgeExtensionEffectUseShader(); + /** + * Returns how many picture profiles are supported by the display. + * + * displayToken + * The token of the display. + */ + static status_t getMaxLayerPictureProfiles(const sp& displayToken, + int32_t* outMaxProfiles); + // ------------------------------------------------------------------------ // surface creation / destruction diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 38c7f2b70a..76362ff272 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -1020,6 +1020,11 @@ public: return binder::Status::ok(); } + binder::Status getMaxLayerPictureProfiles(const sp& /*display*/, + int32_t* /*outMaxProfiles*/) { + return binder::Status::ok(); + } + protected: IBinder* onAsBinder() override { return nullptr; } diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index dfaf8b6c04..4c705bc3d1 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1840,6 +1840,24 @@ void SurfaceFlinger::setGameContentType(const sp& displayToken, bool on })); } +status_t SurfaceFlinger::getMaxLayerPictureProfiles(const sp& displayToken, + int32_t* outMaxProfiles) { + const char* const whence = __func__; + auto future = mScheduler->schedule([=, this]() FTL_FAKE_GUARD(mStateLock) { + const ssize_t index = mCurrentState.displays.indexOfKey(displayToken); + if (index < 0) { + ALOGE("%s: Invalid display token %p", whence, displayToken.get()); + return 0; + } + const DisplayDeviceState& state = mCurrentState.displays.valueAt(index); + return state.maxLayerPictureProfiles > 0 ? state.maxLayerPictureProfiles + : state.hasPictureProcessing ? 1 + : 0; + }); + *outMaxProfiles = future.get(); + return NO_ERROR; +} + status_t SurfaceFlinger::overrideHdrTypes(const sp& displayToken, const std::vector& hdrTypes) { Mutex::Autolock lock(mStateLock); @@ -8759,6 +8777,16 @@ binder::Status SurfaceComposerAIDL::setGameContentType(const sp& displa return binder::Status::ok(); } +binder::Status SurfaceComposerAIDL::getMaxLayerPictureProfiles(const sp& display, + int32_t* outMaxProfiles) { + status_t status = checkAccessPermission(); + if (status != OK) { + return binderStatusFromStatusT(status); + } + mFlinger->getMaxLayerPictureProfiles(display, outMaxProfiles); + return binder::Status::ok(); +} + binder::Status SurfaceComposerAIDL::captureDisplay( const DisplayCaptureArgs& args, const sp& captureListener) { mFlinger->captureDisplay(args, captureListener); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index cbe2739664..211f37478a 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -596,6 +596,7 @@ private: status_t getHdrOutputConversionSupport(bool* outSupport) const; void setAutoLowLatencyMode(const sp& displayToken, bool on); void setGameContentType(const sp& displayToken, bool on); + status_t getMaxLayerPictureProfiles(const sp& displayToken, int32_t* outMaxProfiles); void setPowerMode(const sp& displayToken, int mode); status_t overrideHdrTypes(const sp& displayToken, const std::vector& hdrTypes); @@ -1533,6 +1534,8 @@ public: binder::Status getHdrOutputConversionSupport(bool* outSupport) override; binder::Status setAutoLowLatencyMode(const sp& display, bool on) override; binder::Status setGameContentType(const sp& display, bool on) override; + binder::Status getMaxLayerPictureProfiles(const sp& display, + int32_t* outMaxProfiles) override; binder::Status captureDisplay(const DisplayCaptureArgs&, const sp&) override; binder::Status captureDisplayById(int64_t, const CaptureArgs&, -- cgit v1.2.3-59-g8ed1b From bee19021e3f9136d3762d764144c738da13f4bde Mon Sep 17 00:00:00 2001 From: ramindani Date: Tue, 29 Oct 2024 09:20:22 -0700 Subject: Adds getSupportedRefreshRates support Source values for refresh rates from the RefreshRateSelector through SurfaceComposerClient. Test: atest android.display.cts.DisplayTest BUG: 365163968 Flag: com.android.server.display.feature.flags.enable_get_supported_refresh_rates Change-Id: I149e6e51b3b3718ef53e522f1fca5650dbbd8b7b --- libs/gui/SurfaceComposerClient.cpp | 5 +++++ libs/gui/aidl/android/gui/DynamicDisplayInfo.aidl | 3 +++ libs/ui/include/ui/DynamicDisplayInfo.h | 3 +++ services/surfaceflinger/Scheduler/RefreshRateSelector.cpp | 13 +++++++++++++ services/surfaceflinger/Scheduler/RefreshRateSelector.h | 2 ++ services/surfaceflinger/SurfaceFlinger.cpp | 7 +++++++ 6 files changed, 33 insertions(+) (limited to 'libs/gui/SurfaceComposerClient.cpp') diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 61aabaa7f6..2603977466 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -2873,6 +2873,11 @@ void SurfaceComposerClient::getDynamicDisplayInfoInternal(gui::DynamicDisplayInf outInfo->hasArrSupport = ginfo.hasArrSupport; outInfo->frameRateCategoryRate = ui::FrameRateCategoryRate(ginfo.frameRateCategoryRate.normal, ginfo.frameRateCategoryRate.high); + outInfo->supportedRefreshRates.clear(); + outInfo->supportedRefreshRates.reserve(ginfo.supportedRefreshRates.size()); + for (const auto rate : ginfo.supportedRefreshRates) { + outInfo->supportedRefreshRates.push_back(static_cast(rate)); + } } status_t SurfaceComposerClient::getDynamicDisplayInfoFromId(int64_t displayId, diff --git a/libs/gui/aidl/android/gui/DynamicDisplayInfo.aidl b/libs/gui/aidl/android/gui/DynamicDisplayInfo.aidl index 67cc273fce..26c12c56f3 100644 --- a/libs/gui/aidl/android/gui/DynamicDisplayInfo.aidl +++ b/libs/gui/aidl/android/gui/DynamicDisplayInfo.aidl @@ -50,4 +50,7 @@ parcelable DynamicDisplayInfo { // Represents frame rate for FrameRateCategory Normal and High. FrameRateCategoryRate frameRateCategoryRate; + + // All the refresh rates supported for the default display mode. + float[] supportedRefreshRates; } diff --git a/libs/ui/include/ui/DynamicDisplayInfo.h b/libs/ui/include/ui/DynamicDisplayInfo.h index af494dcf39..9d97151155 100644 --- a/libs/ui/include/ui/DynamicDisplayInfo.h +++ b/libs/ui/include/ui/DynamicDisplayInfo.h @@ -59,6 +59,9 @@ struct DynamicDisplayInfo { // Represents frame rate for FrameRateCategory Normal and High. ui::FrameRateCategoryRate frameRateCategoryRate; + + // All the refresh rates supported for the default display mode. + std::vector supportedRefreshRates; }; } // namespace android::ui diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp index 84fa1390a4..7f763e565d 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp +++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp @@ -1569,6 +1569,19 @@ Fps RefreshRateSelector::findClosestKnownFrameRate(Fps frameRate) const { return distance1 < distance2 ? *lowerBound : *std::prev(lowerBound); } +std::vector RefreshRateSelector::getSupportedFrameRates() const { + std::scoped_lock lock(mLock); + // TODO(b/356986687) Remove the limit once we have the anchor list implementation. + const size_t frameRatesSize = std::min(11, mPrimaryFrameRates.size()); + std::vector supportedFrameRates; + supportedFrameRates.reserve(frameRatesSize); + std::transform(mPrimaryFrameRates.rbegin(), + mPrimaryFrameRates.rbegin() + static_cast(frameRatesSize), + std::back_inserter(supportedFrameRates), + [](FrameRateMode mode) { return mode.fps.getValue(); }); + return supportedFrameRates; +} + auto RefreshRateSelector::getIdleTimerAction() const -> KernelIdleTimerAction { std::lock_guard lock(mLock); diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.h b/services/surfaceflinger/Scheduler/RefreshRateSelector.h index ee3a4f7bdc..508f9d72ea 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateSelector.h +++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.h @@ -441,6 +441,8 @@ public: std::pair getFrameRateCategoryRates() const { return kFrameRateCategoryRates; } + std::vector getSupportedFrameRates() const EXCLUDES(mLock); + private: friend struct TestableRefreshRateSelector; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 9854174bbd..de94c264a8 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1229,6 +1229,8 @@ void SurfaceFlinger::getDynamicDisplayInfoInternal(ui::DynamicDisplayInfo*& info const auto [normal, high] = display->refreshRateSelector().getFrameRateCategoryRates(); ui::FrameRateCategoryRate frameRateCategoryRate(normal.getValue(), high.getValue()); info->frameRateCategoryRate = frameRateCategoryRate; + + info->supportedRefreshRates = display->refreshRateSelector().getSupportedFrameRates(); info->activeColorMode = display->getCompositionDisplay()->getState().colorMode; info->hdrCapabilities = filterOut4k30(display->getHdrCapabilities()); @@ -8581,6 +8583,11 @@ void SurfaceComposerAIDL::getDynamicDisplayInfoInternal(ui::DynamicDisplayInfo& gui::FrameRateCategoryRate& frameRateCategoryRate = outInfo->frameRateCategoryRate; frameRateCategoryRate.normal = info.frameRateCategoryRate.getNormal(); frameRateCategoryRate.high = info.frameRateCategoryRate.getHigh(); + outInfo->supportedRefreshRates.clear(); + outInfo->supportedRefreshRates.reserve(info.supportedRefreshRates.size()); + for (float supportedRefreshRate : info.supportedRefreshRates) { + outInfo->supportedRefreshRates.push_back(supportedRefreshRate); + } outInfo->supportedColorModes.clear(); outInfo->supportedColorModes.reserve(info.supportedColorModes.size()); -- cgit v1.2.3-59-g8ed1b