From d3d8f8e3501a07d55090c287ac45943d687b7006 Mon Sep 17 00:00:00 2001 From: Huihong Luo Date: Tue, 8 Mar 2022 14:48:46 -0800 Subject: Migrate ISurfaceComposerClient to AIDL Migrate and clean up ISurfaceComposerClient to aidl, removed the deprecated createWithParent method, removed non used parameters. Bug: 172002646 Test: atest libgui_test Change-Id: I8ceb7cd90104f2ad9ca72c8025f6298de1fb1ba0 --- libs/gui/LayerState.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libs/gui/LayerState.cpp') diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 502031c8d8..3ab9e974bc 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -19,10 +19,10 @@ #include #include +#include #include #include #include -#include #include #include #include -- cgit v1.2.3-59-g8ed1b From 67dd7126b52bf8ab25d89470392b887bccf0ad6f Mon Sep 17 00:00:00 2001 From: Tianhao Yao Date: Tue, 22 Feb 2022 17:48:33 +0000 Subject: Enable drawing layers' borders in SurfaceFlinger. Provide an API on SurfaceComposerClient::Transaction for enabling a border to be drawn for a specified hierarchy. The caller requests a border to be drawn at a certain Layer and all its children will be included when computing the visible region. The border will draw around the union of all the layers' visible regions, starting from the requested layer. Test: go/wm-smoke Test: LayerBorder_test Bug: 225977175 Change-Id: I7760b51b68cdf01bb9146ec91a270a9d63927995 --- libs/gui/LayerState.cpp | 8 +- libs/gui/SurfaceComposerClient.cpp | 15 ++ libs/gui/include/gui/LayerState.h | 4 +- libs/gui/include/gui/SurfaceComposerClient.h | 2 + .../include/renderengine/BorderRenderInfo.h | 33 +++ .../include/renderengine/DisplaySettings.h | 6 +- libs/renderengine/skia/SkiaGLRenderEngine.cpp | 24 ++ libs/renderengine/tests/RenderEngineTest.cpp | 47 ++++ .../compositionengine/CompositionRefreshArgs.h | 5 + .../include/compositionengine/impl/Output.h | 1 + .../impl/OutputCompositionState.h | 2 + .../CompositionEngine/src/Output.cpp | 38 ++++ .../src/OutputCompositionState.cpp | 8 +- services/surfaceflinger/Layer.cpp | 15 +- services/surfaceflinger/Layer.h | 5 + services/surfaceflinger/SurfaceFlinger.cpp | 23 ++ services/surfaceflinger/tests/Android.bp | 1 + services/surfaceflinger/tests/LayerBorder_test.cpp | 247 +++++++++++++++++++++ services/surfaceflinger/tests/utils/ColorUtils.h | 12 + 19 files changed, 490 insertions(+), 6 deletions(-) create mode 100644 libs/renderengine/include/renderengine/BorderRenderInfo.h create mode 100644 services/surfaceflinger/tests/LayerBorder_test.cpp (limited to 'libs/gui/LayerState.cpp') diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 3ab9e974bc..0d3b412842 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -66,6 +66,7 @@ layer_state_t::layer_state_t() fixedTransformHint(ui::Transform::ROT_INVALID), autoRefresh(false), isTrustedOverlay(false), + borderEnabled(false), bufferCrop(Rect::INVALID_RECT), destinationFrame(Rect::INVALID_RECT), dropInputMode(gui::DropInputMode::NONE) { @@ -100,7 +101,7 @@ status_t layer_state_t::write(Parcel& output) const SAFE_PARCEL(output.write, transparentRegion); SAFE_PARCEL(output.writeUint32, transform); SAFE_PARCEL(output.writeBool, transformToDisplayInverse); - + SAFE_PARCEL(output.writeBool, borderEnabled); SAFE_PARCEL(output.writeUint32, static_cast(dataspace)); SAFE_PARCEL(output.write, hdrMetadata); SAFE_PARCEL(output.write, surfaceDamageRegion); @@ -200,6 +201,7 @@ status_t layer_state_t::read(const Parcel& input) SAFE_PARCEL(input.read, transparentRegion); SAFE_PARCEL(input.readUint32, &transform); SAFE_PARCEL(input.readBool, &transformToDisplayInverse); + SAFE_PARCEL(input.readBool, &borderEnabled); uint32_t tmpUint32 = 0; SAFE_PARCEL(input.readUint32, &tmpUint32); @@ -550,6 +552,10 @@ void layer_state_t::merge(const layer_state_t& other) { what |= eShadowRadiusChanged; shadowRadius = other.shadowRadius; } + if (other.what & eRenderBorderChanged) { + what |= eRenderBorderChanged; + borderEnabled = other.borderEnabled; + } if (other.what & eFrameRateSelectionPriority) { what |= eFrameRateSelectionPriority; frameRateSelectionPriority = other.frameRateSelectionPriority; diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 3446b1bc0d..d543e9444c 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1918,6 +1918,21 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setDropI return *this; } +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::enableBorder( + const sp& sc, bool shouldEnable) { + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } + + s->what |= layer_state_t::eRenderBorderChanged; + s->borderEnabled = shouldEnable; + + 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 4cd9a56fcd..4621d2b24e 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -155,7 +155,7 @@ struct layer_state_t { eLayerStackChanged = 0x00000080, eDimmingEnabledChanged = 0x00000400, eShadowRadiusChanged = 0x00000800, - /* unused 0x00001000, */ + eRenderBorderChanged = 0x00001000, eBufferCropChanged = 0x00002000, eRelativeLayerChanged = 0x00004000, eReparent = 0x00008000, @@ -293,6 +293,8 @@ struct layer_state_t { // should be trusted for input occlusion detection purposes bool isTrustedOverlay; + // Flag to indicate if border needs to be enabled on the layer + bool borderEnabled; // Stretch effect to be applied to this layer StretchEffect stretchEffect; diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index dc9624269b..cdb60c713a 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -625,6 +625,8 @@ public: const Rect& destinationFrame); Transaction& setDropInputMode(const sp& sc, gui::DropInputMode mode); + Transaction& enableBorder(const sp& sc, bool shouldEnable); + status_t setDisplaySurface(const sp& token, const sp& bufferProducer); diff --git a/libs/renderengine/include/renderengine/BorderRenderInfo.h b/libs/renderengine/include/renderengine/BorderRenderInfo.h new file mode 100644 index 0000000000..85d55fc958 --- /dev/null +++ b/libs/renderengine/include/renderengine/BorderRenderInfo.h @@ -0,0 +1,33 @@ +/* + * Copyright 2022 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 { +namespace renderengine { + +struct BorderRenderInfo { + Region combinedRegion; + + bool operator==(const BorderRenderInfo& rhs) const { + return (combinedRegion.hasSameRects(rhs.combinedRegion)); + } +}; + +} // namespace renderengine +} // namespace android \ No newline at end of file diff --git a/libs/renderengine/include/renderengine/DisplaySettings.h b/libs/renderengine/include/renderengine/DisplaySettings.h index 59ef991eec..25fe9f2d8e 100644 --- a/libs/renderengine/include/renderengine/DisplaySettings.h +++ b/libs/renderengine/include/renderengine/DisplaySettings.h @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -79,6 +80,8 @@ struct DisplaySettings { // Configures the rendering intent of the output display. This is used for tonemapping. aidl::android::hardware::graphics::composer3::RenderIntent renderIntent = aidl::android::hardware::graphics::composer3::RenderIntent::TONE_MAP_COLORIMETRIC; + + std::vector borderInfoList; }; static inline bool operator==(const DisplaySettings& lhs, const DisplaySettings& rhs) { @@ -90,7 +93,8 @@ static inline bool operator==(const DisplaySettings& lhs, const DisplaySettings& lhs.deviceHandlesColorTransform == rhs.deviceHandlesColorTransform && lhs.orientation == rhs.orientation && lhs.targetLuminanceNits == rhs.targetLuminanceNits && - lhs.dimmingStage == rhs.dimmingStage && lhs.renderIntent == rhs.renderIntent; + lhs.dimmingStage == rhs.dimmingStage && lhs.renderIntent == rhs.renderIntent && + lhs.borderInfoList == rhs.borderInfoList; } static const char* orientation_to_string(uint32_t orientation) { diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp index 11cea1339d..ec9ad54b56 100644 --- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp +++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp @@ -1245,6 +1245,30 @@ void SkiaGLRenderEngine::drawLayersInternal( activeSurface->flush(); } } + for (const auto& borderRenderInfo : display.borderInfoList) { + SkPaint p; + // TODO (b/225977175): Use specified color + p.setColor(SkColor4f{.fR = 255 / 255.0f, + .fG = 128 / 255.0f, + .fB = 0 / 255.0f, + .fA = 255 / 255.0f}); + p.setAntiAlias(true); + p.setStyle(SkPaint::kStroke_Style); + // TODO (b/225977175): Use specified width + p.setStrokeWidth(20); + SkRegion sk_region; + SkPath path; + + // Construct a final SkRegion using Regions + for (const auto& r : borderRenderInfo.combinedRegion) { + sk_region.op({r.left, r.top, r.right, r.bottom}, SkRegion::kUnion_Op); + } + + sk_region.getBoundaryPath(&path); + canvas->drawPath(path, p); + path.close(); + } + surfaceAutoSaveRestore.restore(); mCapture->endCapture(); { diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp index 7c70a748b5..df1b985bd6 100644 --- a/libs/renderengine/tests/RenderEngineTest.cpp +++ b/libs/renderengine/tests/RenderEngineTest.cpp @@ -2411,6 +2411,53 @@ TEST_P(RenderEngineTest, testDisableBlendingBuffer) { expectBufferColor(rect, 0, 128, 0, 128); } +TEST_P(RenderEngineTest, testBorder) { + if (GetParam()->type() != renderengine::RenderEngine::RenderEngineType::SKIA_GL) { + GTEST_SKIP(); + } + + if (!GetParam()->useColorManagement()) { + GTEST_SKIP(); + } + + initializeRenderEngine(); + + const ui::Dataspace dataspace = ui::Dataspace::V0_SRGB; + + const auto displayRect = Rect(1080, 2280); + renderengine::DisplaySettings display{ + .physicalDisplay = displayRect, + .clip = displayRect, + .outputDataspace = dataspace, + }; + display.borderInfoList.clear(); + renderengine::BorderRenderInfo info; + info.combinedRegion = Region(Rect(99, 99, 199, 199)); + display.borderInfoList.emplace_back(info); + + const auto greenBuffer = allocateAndFillSourceBuffer(1, 1, ubyte4(0, 255, 0, 255)); + const renderengine::LayerSettings greenLayer{ + .geometry.boundaries = FloatRect(0.f, 0.f, 1.f, 1.f), + .source = + renderengine::PixelSource{ + .buffer = + renderengine::Buffer{ + .buffer = greenBuffer, + .usePremultipliedAlpha = true, + }, + }, + .alpha = 1.0f, + .sourceDataspace = dataspace, + .whitePointNits = 200.f, + }; + + std::vector layers; + layers.emplace_back(greenLayer); + invokeDraw(display, layers); + + expectBufferColor(Rect(99, 99, 101, 101), 255, 128, 0, 255, 1); +} + TEST_P(RenderEngineTest, testDimming) { if (GetParam()->type() == renderengine::RenderEngine::RenderEngineType::GLES) { GTEST_SKIP(); diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h index f201751d59..8039bbacb9 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h @@ -32,6 +32,9 @@ namespace android::compositionengine { using Layers = std::vector>; using Outputs = std::vector>; +struct BorderRenderInfo { + std::vector layerIds; +}; /** * A parameter object for refreshing a set of outputs */ @@ -90,6 +93,8 @@ struct CompositionRefreshArgs { // If set, a frame has been scheduled for that time. std::optional scheduledFrameTime; + + std::vector borderInfoList; }; } // namespace android::compositionengine diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h index 31c51e6a8d..3ad6e52f26 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h @@ -152,6 +152,7 @@ protected: private: void dirtyEntireOutput(); + void updateCompositionStateForBorder(const compositionengine::CompositionRefreshArgs&); compositionengine::OutputLayer* findLayerRequestingBackgroundComposition() const; void finishPrepareFrame(); ui::Dataspace getBestDataspace(ui::Dataspace*, bool*) const; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h index c65d467b0d..cd56530f37 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h @@ -33,6 +33,7 @@ #pragma clang diagnostic pop // ignored "-Wconversion -Wextra" #include +#include #include #include #include @@ -164,6 +165,7 @@ struct OutputCompositionState { bool treat170mAsSrgb = false; + std::vector borderInfoList; // Debugging void dump(std::string& result) const; }; diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index 4c30f99610..430d6734fe 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -733,6 +733,39 @@ void Output::updateCompositionState(const compositionengine::CompositionRefreshA forceClientComposition = false; } } + + updateCompositionStateForBorder(refreshArgs); +} + +void Output::updateCompositionStateForBorder( + const compositionengine::CompositionRefreshArgs& refreshArgs) { + std::unordered_map layerVisibleRegionMap; + // Store a map of layerId to their computed visible region. + for (auto* layer : getOutputLayersOrderedByZ()) { + int layerId = (layer->getLayerFE()).getSequence(); + layerVisibleRegionMap[layerId] = &((layer->getState()).visibleRegion); + } + OutputCompositionState& outputCompositionState = editState(); + outputCompositionState.borderInfoList.clear(); + bool clientComposeTopLayer = false; + for (const auto& borderInfo : refreshArgs.borderInfoList) { + renderengine::BorderRenderInfo info; + for (const auto& id : borderInfo.layerIds) { + info.combinedRegion.orSelf(*(layerVisibleRegionMap[id])); + } + outputCompositionState.borderInfoList.emplace_back(std::move(info)); + clientComposeTopLayer |= !info.combinedRegion.isEmpty(); + } + + // In this situation we must client compose the top layer instead of using hwc + // because we want to draw the border above all else. + // This could potentially cause a bit of a performance regression if the top + // layer would have been rendered using hwc originally. + // TODO(b/227656283): Measure system's performance before enabling the border feature + if (clientComposeTopLayer) { + auto topLayer = getOutputLayerOrderedByZByIndex(getOutputLayerCount() - 1); + (topLayer->editState()).forceClientComposition = true; + } } void Output::planComposition() { @@ -1183,6 +1216,11 @@ std::optional Output::composeSurfaces( // Compute the global color transform matrix. clientCompositionDisplay.colorTransform = outputState.colorTransformMatrix; + for (auto& info : outputState.borderInfoList) { + renderengine::BorderRenderInfo borderInfo; + borderInfo.combinedRegion = info.combinedRegion; + clientCompositionDisplay.borderInfoList.emplace_back(std::move(borderInfo)); + } clientCompositionDisplay.deviceHandlesColorTransform = outputState.usesDeviceComposition || getSkipColorTransform(); diff --git a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp index 948c0c90bf..c512a1e97f 100644 --- a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp +++ b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp @@ -62,14 +62,18 @@ void OutputCompositionState::dump(std::string& out) const { dumpVal(out, "sdrWhitePointNits", sdrWhitePointNits); dumpVal(out, "clientTargetBrightness", clientTargetBrightness); dumpVal(out, "displayBrightness", displayBrightness); - out.append("\n "); dumpVal(out, "compositionStrategyPredictionState", ftl::enum_string(strategyPrediction)); + out.append("\n "); out.append("\n "); dumpVal(out, "treate170mAsSrgb", treat170mAsSrgb); - out += '\n'; + out.append("\n"); + for (const auto& borderRenderInfo : borderInfoList) { + dumpVal(out, "borderRegion", borderRenderInfo.combinedRegion); + } + out.append("\n"); } } // namespace android::compositionengine::impl diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index af3971749b..d47e423ebe 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -101,7 +101,8 @@ Layer::Layer(const LayerCreationArgs& args) mClientRef(args.client), mWindowType(static_cast( args.metadata.getInt32(gui::METADATA_WINDOW_TYPE, 0))), - mLayerCreationFlags(args.flags) { + mLayerCreationFlags(args.flags), + mBorderEnabled(false) { uint32_t layerFlags = 0; if (args.flags & ISurfaceComposerClient::eHidden) layerFlags |= layer_state_t::eLayerHidden; if (args.flags & ISurfaceComposerClient::eOpaque) layerFlags |= layer_state_t::eLayerOpaque; @@ -1156,6 +1157,18 @@ StretchEffect Layer::getStretchEffect() const { return StretchEffect{}; } +bool Layer::enableBorder(bool shouldEnable) { + if (mBorderEnabled == shouldEnable) { + return false; + } + mBorderEnabled = shouldEnable; + return true; +} + +bool Layer::isBorderEnabled() { + return mBorderEnabled; +} + bool Layer::propagateFrameRateForLayerTree(FrameRate parentFrameRate, bool* transactionNeeded) { // The frame rate for layer tree is this layer's frame rate if present, or the parent frame rate const auto frameRate = [&] { diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index ff18fd0b92..85187e1691 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -895,6 +895,8 @@ public: bool setStretchEffect(const StretchEffect& effect); StretchEffect getStretchEffect() const; + bool enableBorder(bool shouldEnable); + bool isBorderEnabled(); virtual bool setBufferCrop(const Rect& /* bufferCrop */) { return false; } virtual bool setDestinationFrame(const Rect& /* destinationFrame */) { return false; } @@ -1143,7 +1145,10 @@ private: bool mIsAtRoot = false; uint32_t mLayerCreationFlags; + bool findInHierarchy(const sp&); + + bool mBorderEnabled = false; }; std::ostream& operator<<(std::ostream& stream, const Layer::FrameRate& rate); diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 040014d9ce..ec87dbef61 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -156,6 +156,10 @@ #define NO_THREAD_SAFETY_ANALYSIS \ _Pragma("GCC error \"Prefer or MutexUtils.h helpers.\"") +// To enable layer borders in the system, change the below flag to true. +#undef DOES_CONTAIN_BORDER +#define DOES_CONTAIN_BORDER false + namespace android { using namespace std::string_literals; @@ -2169,6 +2173,20 @@ void SurfaceFlinger::composite(nsecs_t frameTime, int64_t vsyncId) if (auto layerFE = layer->getCompositionEngineLayerFE()) refreshArgs.layers.push_back(layerFE); }); + + if (DOES_CONTAIN_BORDER) { + refreshArgs.borderInfoList.clear(); + mDrawingState.traverse([&refreshArgs](Layer* layer) { + if (layer->isBorderEnabled()) { + compositionengine::BorderRenderInfo info; + layer->traverse(LayerVector::StateSet::Drawing, [&info](Layer* ilayer) { + info.layerIds.push_back(ilayer->getSequence()); + }); + refreshArgs.borderInfoList.emplace_back(std::move(info)); + } + }); + } + refreshArgs.layersWithQueuedFrames.reserve(mLayersWithQueuedFrames.size()); for (auto layer : mLayersWithQueuedFrames) { if (auto layerFE = layer->getCompositionEngineLayerFE()) @@ -4429,6 +4447,11 @@ uint32_t SurfaceFlinger::setClientStateLocked(const FrameTimelineInfo& frameTime if (what & layer_state_t::eBlurRegionsChanged) { if (layer->setBlurRegions(s.blurRegions)) flags |= eTraversalNeeded; } + if (what & layer_state_t::eRenderBorderChanged) { + if (layer->enableBorder(s.borderEnabled)) { + flags |= eTraversalNeeded; + } + } if (what & layer_state_t::eLayerStackChanged) { ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer); // We only allow setting layer stacks for top level layers, diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp index ceddf2727a..276431e661 100644 --- a/services/surfaceflinger/tests/Android.bp +++ b/services/surfaceflinger/tests/Android.bp @@ -34,6 +34,7 @@ cc_test { "DisplayConfigs_test.cpp", "DisplayEventReceiver_test.cpp", "EffectLayer_test.cpp", + "LayerBorder_test.cpp", "InvalidHandles_test.cpp", "LayerCallback_test.cpp", "LayerRenderTypeTransaction_test.cpp", diff --git a/services/surfaceflinger/tests/LayerBorder_test.cpp b/services/surfaceflinger/tests/LayerBorder_test.cpp new file mode 100644 index 0000000000..4b382140af --- /dev/null +++ b/services/surfaceflinger/tests/LayerBorder_test.cpp @@ -0,0 +1,247 @@ +/* + * Copyright (C) 2022 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. + */ + +// TODO(b/129481165): remove the #pragma below and fix conversion issues +// TODO: Amend all tests when screenshots become fully reworked for borders +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wconversion" + +#include // std::chrono::seconds +#include // std::this_thread::sleep_for +#include "LayerTransactionTest.h" + +namespace android { + +class LayerBorderTest : public LayerTransactionTest { +protected: + virtual void SetUp() { + LayerTransactionTest::SetUp(); + ASSERT_EQ(NO_ERROR, mClient->initCheck()); + + toHalf3 = ColorTransformHelper::toHalf3; + toHalf4 = ColorTransformHelper::toHalf4; + + const auto display = SurfaceComposerClient::getInternalDisplayToken(); + ASSERT_FALSE(display == nullptr); + + mParentLayer = createColorLayer("Parent layer", Color::RED); + + mContainerLayer = mClient->createSurface(String8("Container Layer"), 0 /* width */, + 0 /* height */, PIXEL_FORMAT_RGBA_8888, + ISurfaceComposerClient::eFXSurfaceContainer | + ISurfaceComposerClient::eNoColorFill, + mParentLayer->getHandle()); + EXPECT_NE(nullptr, mContainerLayer.get()) << "failed to create container layer"; + + mEffectLayer1 = mClient->createSurface(String8("Effect Layer"), 0 /* width */, + 0 /* height */, PIXEL_FORMAT_RGBA_8888, + ISurfaceComposerClient::eFXSurfaceEffect | + ISurfaceComposerClient::eNoColorFill, + mContainerLayer->getHandle()); + EXPECT_NE(nullptr, mEffectLayer1.get()) << "failed to create effect layer 1"; + + mEffectLayer2 = mClient->createSurface(String8("Effect Layer"), 0 /* width */, + 0 /* height */, PIXEL_FORMAT_RGBA_8888, + ISurfaceComposerClient::eFXSurfaceEffect | + ISurfaceComposerClient::eNoColorFill, + mContainerLayer->getHandle()); + + EXPECT_NE(nullptr, mEffectLayer2.get()) << "failed to create effect layer 2"; + + asTransaction([&](Transaction& t) { + t.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK); + t.setLayer(mParentLayer, INT32_MAX - 20).show(mParentLayer); + t.setFlags(mParentLayer, layer_state_t::eLayerOpaque, layer_state_t::eLayerOpaque); + + t.setColor(mEffectLayer1, toHalf3(Color::BLUE)); + + t.setColor(mEffectLayer2, toHalf3(Color::GREEN)); + }); + } + + virtual void TearDown() { + // Uncomment the line right below when running any of the tests + // std::this_thread::sleep_for (std::chrono::seconds(30)); + LayerTransactionTest::TearDown(); + mParentLayer = 0; + } + + std::function toHalf3; + std::function toHalf4; + sp mParentLayer, mContainerLayer, mEffectLayer1, mEffectLayer2; +}; + +TEST_F(LayerBorderTest, OverlappingVisibleRegions) { + asTransaction([&](Transaction& t) { + t.setCrop(mEffectLayer1, Rect(0, 0, 400, 400)); + t.setCrop(mEffectLayer2, Rect(200, 200, 600, 600)); + + t.enableBorder(mContainerLayer, true); + t.show(mEffectLayer1); + t.show(mEffectLayer2); + t.show(mContainerLayer); + }); +} + +TEST_F(LayerBorderTest, PartiallyCoveredVisibleRegion) { + asTransaction([&](Transaction& t) { + t.setCrop(mEffectLayer1, Rect(0, 0, 400, 400)); + t.setCrop(mEffectLayer2, Rect(200, 200, 600, 600)); + + t.enableBorder(mEffectLayer1, true); + t.show(mEffectLayer1); + t.show(mEffectLayer2); + t.show(mContainerLayer); + }); +} + +TEST_F(LayerBorderTest, NonOverlappingVisibleRegion) { + asTransaction([&](Transaction& t) { + t.setCrop(mEffectLayer1, Rect(0, 0, 200, 200)); + t.setCrop(mEffectLayer2, Rect(400, 400, 600, 600)); + + t.enableBorder(mContainerLayer, true); + t.show(mEffectLayer1); + t.show(mEffectLayer2); + t.show(mContainerLayer); + }); +} + +TEST_F(LayerBorderTest, EmptyVisibleRegion) { + asTransaction([&](Transaction& t) { + t.setCrop(mEffectLayer1, Rect(200, 200, 400, 400)); + t.setCrop(mEffectLayer2, Rect(0, 0, 600, 600)); + + t.enableBorder(mEffectLayer1, true); + t.show(mEffectLayer1); + t.show(mEffectLayer2); + t.show(mContainerLayer); + }); +} + +TEST_F(LayerBorderTest, ZOrderAdjustment) { + asTransaction([&](Transaction& t) { + t.setCrop(mEffectLayer1, Rect(0, 0, 400, 400)); + t.setCrop(mEffectLayer2, Rect(200, 200, 600, 600)); + t.setLayer(mParentLayer, 10); + t.setLayer(mEffectLayer1, 30); + t.setLayer(mEffectLayer2, 20); + + t.enableBorder(mEffectLayer1, true); + t.show(mEffectLayer1); + t.show(mEffectLayer2); + t.show(mContainerLayer); + }); +} + +TEST_F(LayerBorderTest, GrandChildHierarchy) { + sp containerLayer2 = + mClient->createSurface(String8("Container Layer"), 0 /* width */, 0 /* height */, + PIXEL_FORMAT_RGBA_8888, + ISurfaceComposerClient::eFXSurfaceContainer | + ISurfaceComposerClient::eNoColorFill, + mContainerLayer->getHandle()); + EXPECT_NE(nullptr, containerLayer2.get()) << "failed to create container layer 2"; + + sp effectLayer3 = + mClient->createSurface(String8("Effect Layer"), 0 /* width */, 0 /* height */, + PIXEL_FORMAT_RGBA_8888, + ISurfaceComposerClient::eFXSurfaceEffect | + ISurfaceComposerClient::eNoColorFill, + containerLayer2->getHandle()); + + asTransaction([&](Transaction& t) { + t.setCrop(mEffectLayer1, Rect(0, 0, 400, 400)); + t.setCrop(mEffectLayer2, Rect(200, 200, 600, 600)); + t.setCrop(effectLayer3, Rect(400, 400, 800, 800)); + t.setColor(effectLayer3, toHalf3(Color::BLUE)); + + t.enableBorder(mContainerLayer, true); + t.show(mEffectLayer1); + t.show(mEffectLayer2); + t.show(effectLayer3); + t.show(mContainerLayer); + }); +} + +TEST_F(LayerBorderTest, TransparentAlpha) { + asTransaction([&](Transaction& t) { + t.setCrop(mEffectLayer1, Rect(0, 0, 400, 400)); + t.setCrop(mEffectLayer2, Rect(200, 200, 600, 600)); + t.setAlpha(mEffectLayer1, 0.0f); + + t.enableBorder(mEffectLayer1, true); + t.show(mEffectLayer1); + t.show(mEffectLayer2); + t.show(mContainerLayer); + }); +} + +TEST_F(LayerBorderTest, SemiTransparentAlpha) { + asTransaction([&](Transaction& t) { + t.setCrop(mEffectLayer1, Rect(0, 0, 400, 400)); + t.setCrop(mEffectLayer2, Rect(200, 200, 600, 600)); + t.setAlpha(mEffectLayer2, 0.5f); + + t.enableBorder(mEffectLayer2, true); + t.show(mEffectLayer1); + t.show(mEffectLayer2); + t.show(mContainerLayer); + }); +} + +TEST_F(LayerBorderTest, InvisibleLayers) { + asTransaction([&](Transaction& t) { + t.setCrop(mEffectLayer1, Rect(0, 0, 400, 400)); + t.setCrop(mEffectLayer2, Rect(200, 200, 600, 600)); + + t.enableBorder(mContainerLayer, true); + t.hide(mEffectLayer2); + t.show(mContainerLayer); + }); +} + +TEST_F(LayerBorderTest, BufferStateLayer) { + asTransaction([&](Transaction& t) { + t.hide(mEffectLayer1); + t.hide(mEffectLayer2); + t.show(mContainerLayer); + + sp bufferStateLayer = + mClient->createSurface(String8("BufferState"), 0 /* width */, 0 /* height */, + PIXEL_FORMAT_RGBA_8888, + ISurfaceComposerClient::eFXSurfaceBufferState, + mContainerLayer->getHandle()); + + sp buffer = + new GraphicBuffer(400, 400, PIXEL_FORMAT_RGBA_8888, 1, + BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN | + BufferUsage::COMPOSER_OVERLAY | BufferUsage::GPU_TEXTURE, + "test"); + TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 200, 200), Color::GREEN); + TransactionUtils::fillGraphicBufferColor(buffer, Rect(200, 200, 400, 400), Color::BLUE); + + t.setBuffer(bufferStateLayer, buffer); + t.setPosition(bufferStateLayer, 100, 100); + t.show(bufferStateLayer); + t.enableBorder(mContainerLayer, true); + }); +} + +} // namespace android + +// TODO(b/129481165): remove the #pragma below and fix conversion issues +#pragma clang diagnostic pop // ignored "-Wconversion" diff --git a/services/surfaceflinger/tests/utils/ColorUtils.h b/services/surfaceflinger/tests/utils/ColorUtils.h index 07916b60a7..38c422a26d 100644 --- a/services/surfaceflinger/tests/utils/ColorUtils.h +++ b/services/surfaceflinger/tests/utils/ColorUtils.h @@ -33,6 +33,10 @@ struct Color { static const Color WHITE; static const Color BLACK; static const Color TRANSPARENT; + + half3 toHalf3() { return half3{r / 255.0f, g / 255.0f, b / 255.0f}; } + + half4 toHalf4() { return half4{r / 255.0f, g / 255.0f, b / 255.0f, a / 255.0f}; } }; const Color Color::RED{255, 0, 0, 255}; @@ -81,6 +85,14 @@ public: } color = ret; } + + static half3 toHalf3(const Color& color) { + return half3{color.r / 255.0f, color.g / 255.0f, color.b / 255.0f}; + } + + static half4 toHalf4(const Color& color) { + return half4{color.r / 255.0f, color.g / 255.0f, color.b / 255.0f, color.a / 255.0f}; + } }; } // namespace } // namespace android -- cgit v1.2.3-59-g8ed1b From 10cea3ca2518916a9bdc2a6f2ead21d760549809 Mon Sep 17 00:00:00 2001 From: Tianhao Yao Date: Wed, 30 Mar 2022 01:37:22 +0000 Subject: Allow using custom widths and colors for layer borders. Update the enableBorder API in SurfaceComposerClient so that width and color can be specified for the border. The information propagates through the pipe all the way to the render engine so it can render the correct color and width for the border Test:go/wm-smoke. Test: LayerBorder_test Bug: 226529222 Change-Id: Id3ab853d5b4d6899a915f729b0d7be701cb5b167 --- libs/gui/LayerState.cpp | 17 +++++++ libs/gui/SurfaceComposerClient.cpp | 4 +- libs/gui/include/gui/LayerState.h | 3 ++ libs/gui/include/gui/SurfaceComposerClient.h | 3 +- .../include/renderengine/BorderRenderInfo.h | 5 +- libs/renderengine/skia/SkiaGLRenderEngine.cpp | 10 ++-- libs/renderengine/tests/RenderEngineTest.cpp | 2 + .../compositionengine/CompositionRefreshArgs.h | 2 + .../CompositionEngine/src/Output.cpp | 11 +++- services/surfaceflinger/Layer.cpp | 14 ++++- services/surfaceflinger/Layer.h | 6 ++- services/surfaceflinger/SurfaceFlinger.cpp | 4 +- services/surfaceflinger/tests/LayerBorder_test.cpp | 59 ++++++++++++++++++---- 13 files changed, 113 insertions(+), 27 deletions(-) (limited to 'libs/gui/LayerState.cpp') diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 0d3b412842..7f0f6381e1 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -102,6 +102,11 @@ status_t layer_state_t::write(Parcel& output) const SAFE_PARCEL(output.writeUint32, transform); SAFE_PARCEL(output.writeBool, transformToDisplayInverse); SAFE_PARCEL(output.writeBool, borderEnabled); + SAFE_PARCEL(output.writeFloat, borderWidth); + SAFE_PARCEL(output.writeFloat, borderColor.r); + SAFE_PARCEL(output.writeFloat, borderColor.g); + SAFE_PARCEL(output.writeFloat, borderColor.b); + SAFE_PARCEL(output.writeFloat, borderColor.a); SAFE_PARCEL(output.writeUint32, static_cast(dataspace)); SAFE_PARCEL(output.write, hdrMetadata); SAFE_PARCEL(output.write, surfaceDamageRegion); @@ -202,6 +207,16 @@ status_t layer_state_t::read(const Parcel& input) SAFE_PARCEL(input.readUint32, &transform); SAFE_PARCEL(input.readBool, &transformToDisplayInverse); SAFE_PARCEL(input.readBool, &borderEnabled); + SAFE_PARCEL(input.readFloat, &tmpFloat); + borderWidth = tmpFloat; + SAFE_PARCEL(input.readFloat, &tmpFloat); + borderColor.r = tmpFloat; + SAFE_PARCEL(input.readFloat, &tmpFloat); + borderColor.g = tmpFloat; + SAFE_PARCEL(input.readFloat, &tmpFloat); + borderColor.b = tmpFloat; + SAFE_PARCEL(input.readFloat, &tmpFloat); + borderColor.a = tmpFloat; uint32_t tmpUint32 = 0; SAFE_PARCEL(input.readUint32, &tmpUint32); @@ -555,6 +570,8 @@ void layer_state_t::merge(const layer_state_t& other) { if (other.what & eRenderBorderChanged) { what |= eRenderBorderChanged; borderEnabled = other.borderEnabled; + borderWidth = other.borderWidth; + borderColor = other.borderColor; } if (other.what & eFrameRateSelectionPriority) { what |= eFrameRateSelectionPriority; diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index caab506cf4..6fc813b043 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1940,7 +1940,7 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setDropI } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::enableBorder( - const sp& sc, bool shouldEnable) { + const sp& sc, bool shouldEnable, float width, const half4& color) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; @@ -1949,6 +1949,8 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::enableBo s->what |= layer_state_t::eRenderBorderChanged; s->borderEnabled = shouldEnable; + s->borderWidth = width; + s->borderColor = color; registerSurfaceControlForCallback(sc); return *this; diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index 4621d2b24e..37a159512f 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -295,6 +295,9 @@ struct layer_state_t { // Flag to indicate if border needs to be enabled on the layer bool borderEnabled; + float borderWidth; + half4 borderColor; + // Stretch effect to be applied to this layer StretchEffect stretchEffect; diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 2b24c3f091..569dbf89c4 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -625,7 +625,8 @@ public: const Rect& destinationFrame); Transaction& setDropInputMode(const sp& sc, gui::DropInputMode mode); - Transaction& enableBorder(const sp& sc, bool shouldEnable); + Transaction& enableBorder(const sp& sc, bool shouldEnable, float width, + const half4& color); status_t setDisplaySurface(const sp& token, const sp& bufferProducer); diff --git a/libs/renderengine/include/renderengine/BorderRenderInfo.h b/libs/renderengine/include/renderengine/BorderRenderInfo.h index 85d55fc958..0ee6661f33 100644 --- a/libs/renderengine/include/renderengine/BorderRenderInfo.h +++ b/libs/renderengine/include/renderengine/BorderRenderInfo.h @@ -22,10 +22,13 @@ namespace android { namespace renderengine { struct BorderRenderInfo { + float width = 0; + half4 color; Region combinedRegion; bool operator==(const BorderRenderInfo& rhs) const { - return (combinedRegion.hasSameRects(rhs.combinedRegion)); + return (width == rhs.width && color == rhs.color && + combinedRegion.hasSameRects(rhs.combinedRegion)); } }; diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp index ec9ad54b56..c9f9ec362a 100644 --- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp +++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp @@ -1247,15 +1247,11 @@ void SkiaGLRenderEngine::drawLayersInternal( } for (const auto& borderRenderInfo : display.borderInfoList) { SkPaint p; - // TODO (b/225977175): Use specified color - p.setColor(SkColor4f{.fR = 255 / 255.0f, - .fG = 128 / 255.0f, - .fB = 0 / 255.0f, - .fA = 255 / 255.0f}); + p.setColor(SkColor4f{borderRenderInfo.color.r, borderRenderInfo.color.g, + borderRenderInfo.color.b, borderRenderInfo.color.a}); p.setAntiAlias(true); p.setStyle(SkPaint::kStroke_Style); - // TODO (b/225977175): Use specified width - p.setStrokeWidth(20); + p.setStrokeWidth(borderRenderInfo.width); SkRegion sk_region; SkPath path; diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp index df1b985bd6..61af698d01 100644 --- a/libs/renderengine/tests/RenderEngineTest.cpp +++ b/libs/renderengine/tests/RenderEngineTest.cpp @@ -2433,6 +2433,8 @@ TEST_P(RenderEngineTest, testBorder) { display.borderInfoList.clear(); renderengine::BorderRenderInfo info; info.combinedRegion = Region(Rect(99, 99, 199, 199)); + info.width = 20.0f; + info.color = half4{1.0f, 128.0f / 255.0f, 0.0f, 1.0f}; display.borderInfoList.emplace_back(info); const auto greenBuffer = allocateAndFillSourceBuffer(1, 1, ubyte4(0, 255, 0, 255)); diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h index 8039bbacb9..f861fc97e4 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h @@ -33,6 +33,8 @@ using Layers = std::vector>; using Outputs = std::vector>; struct BorderRenderInfo { + float width = 0; + half4 color; std::vector layerIds; }; /** diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index 430d6734fe..c65191c6f5 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -753,8 +753,13 @@ void Output::updateCompositionStateForBorder( for (const auto& id : borderInfo.layerIds) { info.combinedRegion.orSelf(*(layerVisibleRegionMap[id])); } - outputCompositionState.borderInfoList.emplace_back(std::move(info)); - clientComposeTopLayer |= !info.combinedRegion.isEmpty(); + + if (!info.combinedRegion.isEmpty()) { + info.width = borderInfo.width; + info.color = borderInfo.color; + outputCompositionState.borderInfoList.emplace_back(std::move(info)); + clientComposeTopLayer = true; + } } // In this situation we must client compose the top layer instead of using hwc @@ -1218,6 +1223,8 @@ std::optional Output::composeSurfaces( clientCompositionDisplay.colorTransform = outputState.colorTransformMatrix; for (auto& info : outputState.borderInfoList) { renderengine::BorderRenderInfo borderInfo; + borderInfo.width = info.width; + borderInfo.color = info.color; borderInfo.combinedRegion = info.combinedRegion; clientCompositionDisplay.borderInfoList.emplace_back(std::move(borderInfo)); } diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index d47e423ebe..2d3b2375e1 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -1157,11 +1157,13 @@ StretchEffect Layer::getStretchEffect() const { return StretchEffect{}; } -bool Layer::enableBorder(bool shouldEnable) { - if (mBorderEnabled == shouldEnable) { +bool Layer::enableBorder(bool shouldEnable, float width, const half4& color) { + if (mBorderEnabled == shouldEnable && mBorderWidth == width && mBorderColor == color) { return false; } mBorderEnabled = shouldEnable; + mBorderWidth = width; + mBorderColor = color; return true; } @@ -1169,6 +1171,14 @@ bool Layer::isBorderEnabled() { return mBorderEnabled; } +float Layer::getBorderWidth() { + return mBorderWidth; +} + +const half4& Layer::getBorderColor() { + return mBorderColor; +} + bool Layer::propagateFrameRateForLayerTree(FrameRate parentFrameRate, bool* transactionNeeded) { // The frame rate for layer tree is this layer's frame rate if present, or the parent frame rate const auto frameRate = [&] { diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 85187e1691..60c97f99fd 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -895,8 +895,10 @@ public: bool setStretchEffect(const StretchEffect& effect); StretchEffect getStretchEffect() const; - bool enableBorder(bool shouldEnable); + bool enableBorder(bool shouldEnable, float width, const half4& color); bool isBorderEnabled(); + float getBorderWidth(); + const half4& getBorderColor(); virtual bool setBufferCrop(const Rect& /* bufferCrop */) { return false; } virtual bool setDestinationFrame(const Rect& /* destinationFrame */) { return false; } @@ -1149,6 +1151,8 @@ private: bool findInHierarchy(const sp&); bool mBorderEnabled = false; + float mBorderWidth; + half4 mBorderColor; }; std::ostream& operator<<(std::ostream& stream, const Layer::FrameRate& rate); diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 1d5d3539b2..82d8580a9b 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2179,6 +2179,8 @@ void SurfaceFlinger::composite(nsecs_t frameTime, int64_t vsyncId) mDrawingState.traverse([&refreshArgs](Layer* layer) { if (layer->isBorderEnabled()) { compositionengine::BorderRenderInfo info; + info.width = layer->getBorderWidth(); + info.color = layer->getBorderColor(); layer->traverse(LayerVector::StateSet::Drawing, [&info](Layer* ilayer) { info.layerIds.push_back(ilayer->getSequence()); }); @@ -4462,7 +4464,7 @@ uint32_t SurfaceFlinger::setClientStateLocked(const FrameTimelineInfo& frameTime if (layer->setBlurRegions(s.blurRegions)) flags |= eTraversalNeeded; } if (what & layer_state_t::eRenderBorderChanged) { - if (layer->enableBorder(s.borderEnabled)) { + if (layer->enableBorder(s.borderEnabled, s.borderWidth, s.borderColor)) { flags |= eTraversalNeeded; } } diff --git a/services/surfaceflinger/tests/LayerBorder_test.cpp b/services/surfaceflinger/tests/LayerBorder_test.cpp index 4b382140af..f80c7055da 100644 --- a/services/surfaceflinger/tests/LayerBorder_test.cpp +++ b/services/surfaceflinger/tests/LayerBorder_test.cpp @@ -36,7 +36,7 @@ protected: const auto display = SurfaceComposerClient::getInternalDisplayToken(); ASSERT_FALSE(display == nullptr); - + mColorOrange = toHalf4({255, 140, 0, 255}); mParentLayer = createColorLayer("Parent layer", Color::RED); mContainerLayer = mClient->createSurface(String8("Container Layer"), 0 /* width */, @@ -82,6 +82,7 @@ protected: std::function toHalf3; std::function toHalf4; sp mParentLayer, mContainerLayer, mEffectLayer1, mEffectLayer2; + half4 mColorOrange; }; TEST_F(LayerBorderTest, OverlappingVisibleRegions) { @@ -89,7 +90,7 @@ TEST_F(LayerBorderTest, OverlappingVisibleRegions) { t.setCrop(mEffectLayer1, Rect(0, 0, 400, 400)); t.setCrop(mEffectLayer2, Rect(200, 200, 600, 600)); - t.enableBorder(mContainerLayer, true); + t.enableBorder(mContainerLayer, true, 20, mColorOrange); t.show(mEffectLayer1); t.show(mEffectLayer2); t.show(mContainerLayer); @@ -101,7 +102,7 @@ TEST_F(LayerBorderTest, PartiallyCoveredVisibleRegion) { t.setCrop(mEffectLayer1, Rect(0, 0, 400, 400)); t.setCrop(mEffectLayer2, Rect(200, 200, 600, 600)); - t.enableBorder(mEffectLayer1, true); + t.enableBorder(mEffectLayer1, true, 20, mColorOrange); t.show(mEffectLayer1); t.show(mEffectLayer2); t.show(mContainerLayer); @@ -113,7 +114,7 @@ TEST_F(LayerBorderTest, NonOverlappingVisibleRegion) { t.setCrop(mEffectLayer1, Rect(0, 0, 200, 200)); t.setCrop(mEffectLayer2, Rect(400, 400, 600, 600)); - t.enableBorder(mContainerLayer, true); + t.enableBorder(mContainerLayer, true, 20, mColorOrange); t.show(mEffectLayer1); t.show(mEffectLayer2); t.show(mContainerLayer); @@ -125,7 +126,7 @@ TEST_F(LayerBorderTest, EmptyVisibleRegion) { t.setCrop(mEffectLayer1, Rect(200, 200, 400, 400)); t.setCrop(mEffectLayer2, Rect(0, 0, 600, 600)); - t.enableBorder(mEffectLayer1, true); + t.enableBorder(mEffectLayer1, true, 20, mColorOrange); t.show(mEffectLayer1); t.show(mEffectLayer2); t.show(mContainerLayer); @@ -140,7 +141,7 @@ TEST_F(LayerBorderTest, ZOrderAdjustment) { t.setLayer(mEffectLayer1, 30); t.setLayer(mEffectLayer2, 20); - t.enableBorder(mEffectLayer1, true); + t.enableBorder(mEffectLayer1, true, 20, mColorOrange); t.show(mEffectLayer1); t.show(mEffectLayer2); t.show(mContainerLayer); @@ -169,7 +170,7 @@ TEST_F(LayerBorderTest, GrandChildHierarchy) { t.setCrop(effectLayer3, Rect(400, 400, 800, 800)); t.setColor(effectLayer3, toHalf3(Color::BLUE)); - t.enableBorder(mContainerLayer, true); + t.enableBorder(mContainerLayer, true, 20, mColorOrange); t.show(mEffectLayer1); t.show(mEffectLayer2); t.show(effectLayer3); @@ -183,7 +184,7 @@ TEST_F(LayerBorderTest, TransparentAlpha) { t.setCrop(mEffectLayer2, Rect(200, 200, 600, 600)); t.setAlpha(mEffectLayer1, 0.0f); - t.enableBorder(mEffectLayer1, true); + t.enableBorder(mContainerLayer, true, 20, mColorOrange); t.show(mEffectLayer1); t.show(mEffectLayer2); t.show(mContainerLayer); @@ -196,7 +197,7 @@ TEST_F(LayerBorderTest, SemiTransparentAlpha) { t.setCrop(mEffectLayer2, Rect(200, 200, 600, 600)); t.setAlpha(mEffectLayer2, 0.5f); - t.enableBorder(mEffectLayer2, true); + t.enableBorder(mEffectLayer2, true, 20, mColorOrange); t.show(mEffectLayer1); t.show(mEffectLayer2); t.show(mContainerLayer); @@ -208,7 +209,7 @@ TEST_F(LayerBorderTest, InvisibleLayers) { t.setCrop(mEffectLayer1, Rect(0, 0, 400, 400)); t.setCrop(mEffectLayer2, Rect(200, 200, 600, 600)); - t.enableBorder(mContainerLayer, true); + t.enableBorder(mContainerLayer, true, 20, mColorOrange); t.hide(mEffectLayer2); t.show(mContainerLayer); }); @@ -237,7 +238,43 @@ TEST_F(LayerBorderTest, BufferStateLayer) { t.setBuffer(bufferStateLayer, buffer); t.setPosition(bufferStateLayer, 100, 100); t.show(bufferStateLayer); - t.enableBorder(mContainerLayer, true); + t.enableBorder(mContainerLayer, true, 20, mColorOrange); + }); +} + +TEST_F(LayerBorderTest, CustomWidth) { + asTransaction([&](Transaction& t) { + t.setCrop(mEffectLayer1, Rect(0, 0, 400, 400)); + t.setCrop(mEffectLayer2, Rect(200, 200, 600, 600)); + + t.enableBorder(mContainerLayer, true, 50, mColorOrange); + t.show(mEffectLayer1); + t.show(mEffectLayer2); + t.show(mContainerLayer); + }); +} + +TEST_F(LayerBorderTest, CustomColor) { + asTransaction([&](Transaction& t) { + t.setCrop(mEffectLayer1, Rect(0, 0, 400, 400)); + t.setCrop(mEffectLayer2, Rect(200, 200, 600, 600)); + + t.enableBorder(mContainerLayer, true, 20, toHalf4({255, 0, 255, 255})); + t.show(mEffectLayer1); + t.show(mEffectLayer2); + t.show(mContainerLayer); + }); +} + +TEST_F(LayerBorderTest, CustomWidthAndColorAndOpacity) { + asTransaction([&](Transaction& t) { + t.setCrop(mEffectLayer1, Rect(0, 0, 200, 200)); + t.setCrop(mEffectLayer2, Rect(400, 400, 600, 600)); + + t.enableBorder(mContainerLayer, true, 40, toHalf4({255, 255, 0, 128})); + t.show(mEffectLayer1); + t.show(mEffectLayer2); + t.show(mContainerLayer); }); } -- cgit v1.2.3-59-g8ed1b From 641f7f22ab6608144c9abbb117cb383298419673 Mon Sep 17 00:00:00 2001 From: Patrick Williams Date: Wed, 22 Jun 2022 19:25:35 +0000 Subject: Update syncInputWindows to use a callback. Adds callbacks to InputWindowCommands and updates SurfaceComposerClient::Transaction::syncInputWindows to use those callbacks. A subsequent CL will replace syncInputWindows with a method that adds user defined callbacks to InputWindowCommands. The condition variable added to SurfaceComposerClient::Transaction is used to retain syncInputWindows' existing behavior and will be removed once users can define callbacks. Bug: b/222421815 Test: manual, TransactionApplicationTest, SwitchImeWindowsFromGestureNavTest Change-Id: Ib582aded1e42f5e049ebe21d5f2ccedf4cf7d654 --- libs/gui/LayerState.cpp | 27 ++++++-- libs/gui/SurfaceComposerClient.cpp | 44 ++++++++++++- libs/gui/include/gui/LayerState.h | 5 +- libs/gui/include/gui/SurfaceComposerClient.h | 18 ++++++ services/surfaceflinger/SurfaceFlinger.cpp | 32 +++++----- services/surfaceflinger/SurfaceFlinger.h | 1 - services/surfaceflinger/TransactionState.h | 1 - .../surfaceflinger/WindowInfosListenerInvoker.cpp | 71 ++++++++++++++------- .../surfaceflinger/WindowInfosListenerInvoker.h | 10 ++- .../fuzzer/surfaceflinger_fuzzer.cpp | 1 - .../tests/unittests/TransactionApplicationTest.cpp | 73 ++++++++-------------- 11 files changed, 180 insertions(+), 103 deletions(-) (limited to 'libs/gui/LayerState.cpp') diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 7f0f6381e1..59c4c5db8a 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -664,29 +664,44 @@ bool InputWindowCommands::merge(const InputWindowCommands& other) { changes |= !other.focusRequests.empty(); focusRequests.insert(focusRequests.end(), std::make_move_iterator(other.focusRequests.begin()), std::make_move_iterator(other.focusRequests.end())); - changes |= other.syncInputWindows && !syncInputWindows; - syncInputWindows |= other.syncInputWindows; + changes |= !other.windowInfosReportedListeners.empty(); + windowInfosReportedListeners.insert(other.windowInfosReportedListeners.begin(), + other.windowInfosReportedListeners.end()); return changes; } bool InputWindowCommands::empty() const { - return focusRequests.empty() && !syncInputWindows; + return focusRequests.empty() && windowInfosReportedListeners.empty(); } void InputWindowCommands::clear() { focusRequests.clear(); - syncInputWindows = false; + windowInfosReportedListeners.clear(); } status_t InputWindowCommands::write(Parcel& output) const { SAFE_PARCEL(output.writeParcelableVector, focusRequests); - SAFE_PARCEL(output.writeBool, syncInputWindows); + + SAFE_PARCEL(output.writeInt32, windowInfosReportedListeners.size()); + for (const auto& listener : windowInfosReportedListeners) { + SAFE_PARCEL(output.writeStrongBinder, listener); + } + return NO_ERROR; } status_t InputWindowCommands::read(const Parcel& input) { SAFE_PARCEL(input.readParcelableVector, &focusRequests); - SAFE_PARCEL(input.readBool, &syncInputWindows); + + int listenerSize = 0; + SAFE_PARCEL_READ_SIZE(input.readInt32, &listenerSize, input.dataSize()); + windowInfosReportedListeners.reserve(listenerSize); + for (int i = 0; i < listenerSize; i++) { + sp listener; + SAFE_PARCEL(input.readStrongBinder, &listener); + windowInfosReportedListeners.insert(listener); + } + return NO_ERROR; } diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 7191de8f7f..647a22cbe9 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -635,7 +636,8 @@ SurfaceComposerClient::Transaction::Transaction(const Transaction& other) mDesiredPresentTime(other.mDesiredPresentTime), mIsAutoTimestamp(other.mIsAutoTimestamp), mFrameTimelineInfo(other.mFrameTimelineInfo), - mApplyToken(other.mApplyToken) { + mApplyToken(other.mApplyToken), + mWindowInfosReportedEvent(other.mWindowInfosReportedEvent) { mDisplayStates = other.mDisplayStates; mComposerStates = other.mComposerStates; mInputWindowCommands = other.mInputWindowCommands; @@ -879,6 +881,9 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Tr mEarlyWakeupStart = mEarlyWakeupStart || other.mEarlyWakeupStart; mEarlyWakeupEnd = mEarlyWakeupEnd || other.mEarlyWakeupEnd; mApplyToken = other.mApplyToken; + if (other.mWindowInfosReportedEvent) { + mWindowInfosReportedEvent = std::move(other.mWindowInfosReportedEvent); + } mergeFrameTimelineInfo(mFrameTimelineInfo, other.mFrameTimelineInfo); @@ -901,6 +906,7 @@ void SurfaceComposerClient::Transaction::clear() { mIsAutoTimestamp = true; clearFrameTimelineInfo(mFrameTimelineInfo); mApplyToken = nullptr; + mWindowInfosReportedEvent = nullptr; } uint64_t SurfaceComposerClient::Transaction::getId() { @@ -1047,6 +1053,10 @@ status_t SurfaceComposerClient::Transaction::apply(bool synchronous, bool oneWay hasListenerCallbacks, listenerCallbacks, mId); mId = generateId(); + if (mWindowInfosReportedEvent && !mWindowInfosReportedEvent->wait()) { + ALOGE("Timed out waiting for window infos to be reported."); + } + // Clear the current states and flags clear(); @@ -1733,8 +1743,25 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFocus return *this; } +class NotifyWindowInfosReported : public gui::BnWindowInfosReportedListener { +public: + NotifyWindowInfosReported( + std::shared_ptr windowInfosReportedEvent) + : mWindowInfosReportedEvent(windowInfosReportedEvent) {} + + binder::Status onWindowInfosReported() { + mWindowInfosReportedEvent->set(); + return binder::Status::ok(); + } + +private: + std::shared_ptr mWindowInfosReportedEvent; +}; + SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::syncInputWindows() { - mInputWindowCommands.syncInputWindows = true; + mWindowInfosReportedEvent = std::make_shared(); + mInputWindowCommands.windowInfosReportedListeners.insert( + sp::make(mWindowInfosReportedEvent)); return *this; } @@ -2809,4 +2836,17 @@ void ReleaseCallbackThread::threadMain() { } } +// --------------------------------------------------------------------------------- + +void SurfaceComposerClient::Event::set() { + std::lock_guard lock(mMutex); + mComplete = true; + mConditionVariable.notify_all(); +} + +bool SurfaceComposerClient::Event::wait() { + std::unique_lock lock(mMutex); + return mConditionVariable.wait_for(lock, sTimeout, [this] { return mComplete; }); +} + } // namespace android diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index 37a159512f..423cd8409d 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -359,7 +360,9 @@ struct DisplayState { struct InputWindowCommands { std::vector focusRequests; - bool syncInputWindows{false}; + std::unordered_set, + SpHash> + windowInfosReportedListeners; // Merges the passed in commands and returns true if there were any changes. bool merge(const InputWindowCommands& other); diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 9f036a6fb1..0927363cfe 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -387,6 +387,22 @@ public: std::unordered_set, SCHash> surfaceControls; }; + // TODO(b/222421815) this class should be removed when + // SurfaceComposerClient::Transaction::syncInputWindows is removed and replaced with a method + // for adding callbacks to InputWindowCommands. + class Event { + private: + static constexpr std::chrono::seconds sTimeout{5}; + + bool mComplete = false; + std::condition_variable mConditionVariable; + std::mutex mMutex; + + public: + void set(); + bool wait(); + }; + class Transaction : public Parcelable { private: void releaseBufferIfOverwriting(const layer_state_t& state); @@ -436,6 +452,8 @@ public: InputWindowCommands mInputWindowCommands; int mStatus = NO_ERROR; + std::shared_ptr mWindowInfosReportedEvent = nullptr; + layer_state_t* getLayerState(const sp& sc); DisplayState& getDisplayState(const sp& token); diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index aba7998b3c..d701221758 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -341,7 +341,7 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory, SkipInitializationTag) mInternalDisplayDensity(getDensityFromProperty("ro.sf.lcd_density", true)), mEmulatedDisplayDensity(getDensityFromProperty("qemu.sf.lcd_density", false)), mPowerAdvisor(std::make_unique(*this)), - mWindowInfosListenerInvoker(sp::make(*this)) { + mWindowInfosListenerInvoker(sp::make()) { ALOGI("Using HWComposer service: %s", mHwcServiceName.c_str()); } @@ -3273,12 +3273,17 @@ void SurfaceFlinger::updateInputFlinger() { inputFlinger = mInputFlinger, this]() { ATRACE_NAME("BackgroundExecutor::updateInputFlinger"); if (updateWindowInfo) { - mWindowInfosListenerInvoker->windowInfosChanged(windowInfos, displayInfos, - inputWindowCommands.syncInputWindows); - } else if (inputWindowCommands.syncInputWindows) { - // If the caller requested to sync input windows, but there are no - // changes to input windows, notify immediately. - windowInfosReported(); + mWindowInfosListenerInvoker + ->windowInfosChanged(windowInfos, displayInfos, + inputWindowCommands.windowInfosReportedListeners); + } else { + // If there are listeners but no changes to input windows, call the listeners + // immediately. + for (const auto& listener : inputWindowCommands.windowInfosReportedListeners) { + if (IInterface::asBinder(listener)->isBinderAlive()) { + listener->onWindowInfosReported(); + } + } } for (const auto& focusRequest : inputWindowCommands.focusRequests) { inputFlinger->setFocusedWindow(focusRequest); @@ -4101,11 +4106,9 @@ void SurfaceFlinger::queueTransaction(TransactionState& state) { Mutex::Autolock lock(mQueueLock); // Generate a CountDownLatch pending state if this is a synchronous transaction. - if ((state.flags & eSynchronous) || state.inputWindowCommands.syncInputWindows) { - state.transactionCommittedSignal = std::make_shared( - (state.inputWindowCommands.syncInputWindows - ? (CountDownLatch::eSyncInputWindows | CountDownLatch::eSyncTransaction) - : CountDownLatch::eSyncTransaction)); + if (state.flags & eSynchronous) { + state.transactionCommittedSignal = + std::make_shared(CountDownLatch::eSyncTransaction); } mTransactionQueue.emplace_back(state); @@ -6803,11 +6806,6 @@ ftl::SharedFuture SurfaceFlinger::renderScreenImpl( return future; } -void SurfaceFlinger::windowInfosReported() { - Mutex::Autolock _l(mStateLock); - signalSynchronousTransactions(CountDownLatch::eSyncInputWindows); -} - // --------------------------------------------------------------------------- void SurfaceFlinger::State::traverse(const LayerVector::Visitor& visitor) const { diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index e1a4cd3e9a..ed6c8ce6d7 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -333,7 +333,6 @@ public: // If set, disables reusing client composition buffers. This can be set by // debug.sf.disable_client_composition_cache bool mDisableClientCompositionCache = false; - void windowInfosReported(); // Disables expensive rendering for all displays // This is scheduled on the main thread diff --git a/services/surfaceflinger/TransactionState.h b/services/surfaceflinger/TransactionState.h index 900d566942..bbfeac1643 100644 --- a/services/surfaceflinger/TransactionState.h +++ b/services/surfaceflinger/TransactionState.h @@ -106,7 +106,6 @@ class CountDownLatch { public: enum { eSyncTransaction = 1 << 0, - eSyncInputWindows = 1 << 1, }; explicit CountDownLatch(uint32_t flags) : mFlags(flags) {} diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.cpp b/services/surfaceflinger/WindowInfosListenerInvoker.cpp index 30b9d8f1cb..cc33001a8b 100644 --- a/services/surfaceflinger/WindowInfosListenerInvoker.cpp +++ b/services/surfaceflinger/WindowInfosListenerInvoker.cpp @@ -26,21 +26,39 @@ using gui::DisplayInfo; using gui::IWindowInfosListener; using gui::WindowInfo; -struct WindowInfosListenerInvoker::WindowInfosReportedListener - : gui::BnWindowInfosReportedListener { - explicit WindowInfosReportedListener(WindowInfosListenerInvoker& invoker) : mInvoker(invoker) {} +struct WindowInfosListenerInvoker::WindowInfosReportedListener : gui::BnWindowInfosReportedListener, + DeathRecipient { + explicit WindowInfosReportedListener( + size_t callbackCount, + const std::unordered_set, + SpHash>& + windowInfosReportedListeners) + : mCallbacksPending(callbackCount), + mWindowInfosReportedListeners(windowInfosReportedListeners) {} binder::Status onWindowInfosReported() override { - mInvoker.windowInfosReported(); + // TODO(b/222421815) There could potentially be callbacks that we don't need to wait for + // before calling the WindowInfosReportedListeners coming from InputWindowCommands. Filter + // the list of callbacks down to those from system server. + if (--mCallbacksPending == 0) { + for (const auto& listener : mWindowInfosReportedListeners) { + sp asBinder = IInterface::asBinder(listener); + if (asBinder->isBinderAlive()) { + listener->onWindowInfosReported(); + } + } + } return binder::Status::ok(); } - WindowInfosListenerInvoker& mInvoker; -}; + void binderDied(const wp&) { onWindowInfosReported(); } -WindowInfosListenerInvoker::WindowInfosListenerInvoker(SurfaceFlinger& flinger) - : mFlinger(flinger), - mWindowInfosReportedListener(sp::make(*this)) {} +private: + std::atomic mCallbacksPending; + std::unordered_set, + SpHash> + mWindowInfosReportedListeners; +}; void WindowInfosListenerInvoker::addWindowInfosListener(sp listener) { sp asBinder = IInterface::asBinder(listener); @@ -64,9 +82,11 @@ void WindowInfosListenerInvoker::binderDied(const wp& who) { mWindowInfosListeners.erase(who); } -void WindowInfosListenerInvoker::windowInfosChanged(const std::vector& windowInfos, - const std::vector& displayInfos, - bool shouldSync) { +void WindowInfosListenerInvoker::windowInfosChanged( + const std::vector& windowInfos, const std::vector& displayInfos, + const std::unordered_set, + SpHash>& + windowInfosReportedListeners) { ftl::SmallVector, kStaticCapacity> windowInfosListeners; { std::scoped_lock lock(mListenersMutex); @@ -75,18 +95,25 @@ void WindowInfosListenerInvoker::windowInfosChanged(const std::vector::make(windowInfosListeners.size(), + windowInfosReportedListeners); for (const auto& listener : windowInfosListeners) { - listener->onWindowInfosChanged(windowInfos, displayInfos, - shouldSync ? mWindowInfosReportedListener : nullptr); - } -} + sp asBinder = IInterface::asBinder(listener); + + // linkToDeath is used here to ensure that the windowInfosReportedListeners + // are called even if one of the windowInfosListeners dies before + // calling onWindowInfosReported. + if (windowInfosReportedListener) { + asBinder->linkToDeath(windowInfosReportedListener); + } -void WindowInfosListenerInvoker::windowInfosReported() { - mCallbacksPending--; - if (mCallbacksPending == 0) { - mFlinger.windowInfosReported(); + auto status = listener->onWindowInfosChanged(windowInfos, displayInfos, + windowInfosReportedListener); + if (!status.isOk()) { + windowInfosReportedListener->onWindowInfosReported(); + } } } diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.h b/services/surfaceflinger/WindowInfosListenerInvoker.h index d8d8d0f570..a1d66a186e 100644 --- a/services/surfaceflinger/WindowInfosListenerInvoker.h +++ b/services/surfaceflinger/WindowInfosListenerInvoker.h @@ -29,22 +29,21 @@ class SurfaceFlinger; class WindowInfosListenerInvoker : public IBinder::DeathRecipient { public: - explicit WindowInfosListenerInvoker(SurfaceFlinger&); - void addWindowInfosListener(sp); void removeWindowInfosListener(const sp& windowInfosListener); void windowInfosChanged(const std::vector&, - const std::vector&, bool shouldSync); + const std::vector&, + const std::unordered_set, + SpHash>& + windowInfosReportedListeners); protected: void binderDied(const wp& who) override; private: struct WindowInfosReportedListener; - void windowInfosReported(); - SurfaceFlinger& mFlinger; std::mutex mListenersMutex; static constexpr size_t kStaticCapacity = 3; @@ -52,7 +51,6 @@ private: mWindowInfosListeners GUARDED_BY(mListenersMutex); sp mWindowInfosReportedListener; - std::atomic mCallbacksPending{0}; }; } // namespace android diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp index f25043cd6d..8e60247c2d 100644 --- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp +++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp @@ -151,7 +151,6 @@ void SurfaceFlingerFuzzer::invokeFlinger() { sp handle = defaultServiceManager()->checkService( String16(mFdp.ConsumeRandomLengthString().c_str())); mFlinger->fromHandle(handle); - mFlinger->windowInfosReported(); mFlinger->disableExpensiveRendering(); } diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp index ded75318ed..84f11704d0 100644 --- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp @@ -107,22 +107,20 @@ public: EXPECT_EQ(info.desiredPresentTime, state.desiredPresentTime); } - void setupSingle(TransactionInfo& transaction, uint32_t flags, bool syncInputWindows, - int64_t desiredPresentTime, bool isAutoTimestamp, - const FrameTimelineInfo& frameTimelineInfo) { + void setupSingle(TransactionInfo& transaction, uint32_t flags, int64_t desiredPresentTime, + bool isAutoTimestamp, const FrameTimelineInfo& frameTimelineInfo) { mTransactionNumber++; transaction.flags |= flags; // ISurfaceComposer::eSynchronous; - transaction.inputWindowCommands.syncInputWindows = syncInputWindows; transaction.desiredPresentTime = desiredPresentTime; transaction.isAutoTimestamp = isAutoTimestamp; transaction.frameTimelineInfo = frameTimelineInfo; } - void NotPlacedOnTransactionQueue(uint32_t flags, bool syncInputWindows) { + void NotPlacedOnTransactionQueue(uint32_t flags) { ASSERT_EQ(0u, mFlinger.getTransactionQueue().size()); EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1); TransactionInfo transaction; - setupSingle(transaction, flags, syncInputWindows, + setupSingle(transaction, flags, /*desiredPresentTime*/ systemTime(), /*isAutoTimestamp*/ true, FrameTimelineInfo{}); nsecs_t applicationTime = systemTime(); @@ -133,12 +131,10 @@ public: transaction.uncacheBuffer, mHasListenerCallbacks, mCallbacks, transaction.id); - // If transaction is synchronous or syncs input windows, SF - // applyTransactionState should time out (5s) wating for SF to commit - // the transaction or to receive a signal that syncInputWindows has - // completed. If this is animation, it should not time out waiting. + // If transaction is synchronous, SF applyTransactionState should time out (5s) wating for + // SF to commit the transaction. If this is animation, it should not time out waiting. nsecs_t returnedTime = systemTime(); - if (flags & ISurfaceComposer::eSynchronous || syncInputWindows) { + if (flags & ISurfaceComposer::eSynchronous) { EXPECT_GE(returnedTime, applicationTime + mFlinger.getAnimationTransactionTimeout()); } else { EXPECT_LE(returnedTime, applicationTime + mFlinger.getAnimationTransactionTimeout()); @@ -148,7 +144,7 @@ public: EXPECT_EQ(1u, transactionQueue.size()); } - void PlaceOnTransactionQueue(uint32_t flags, bool syncInputWindows) { + void PlaceOnTransactionQueue(uint32_t flags) { ASSERT_EQ(0u, mFlinger.getTransactionQueue().size()); EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1); @@ -156,8 +152,8 @@ public: // but afterwards it will look like the desired present time has passed nsecs_t time = systemTime(); TransactionInfo transaction; - setupSingle(transaction, flags, syncInputWindows, - /*desiredPresentTime*/ time + s2ns(1), false, FrameTimelineInfo{}); + setupSingle(transaction, flags, /*desiredPresentTime*/ time + s2ns(1), false, + FrameTimelineInfo{}); nsecs_t applicationSentTime = systemTime(); mFlinger.setTransactionState(transaction.frameTimelineInfo, transaction.states, transaction.displays, transaction.flags, @@ -167,7 +163,7 @@ public: transaction.id); nsecs_t returnedTime = systemTime(); - if ((flags & ISurfaceComposer::eSynchronous) || syncInputWindows) { + if (flags & ISurfaceComposer::eSynchronous) { EXPECT_GE(systemTime(), applicationSentTime + mFlinger.getAnimationTransactionTimeout()); } else { @@ -179,25 +175,21 @@ public: EXPECT_EQ(1u, transactionQueue.size()); } - void BlockedByPriorTransaction(uint32_t flags, bool syncInputWindows) { + void BlockedByPriorTransaction(uint32_t flags) { ASSERT_EQ(0u, mFlinger.getTransactionQueue().size()); nsecs_t time = systemTime(); - if (!syncInputWindows) { - EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(2); - } else { - EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1); - } + EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(2); + // transaction that should go on the pending thread TransactionInfo transactionA; - setupSingle(transactionA, /*flags*/ 0, /*syncInputWindows*/ false, - /*desiredPresentTime*/ time + s2ns(1), false, FrameTimelineInfo{}); + setupSingle(transactionA, /*flags*/ 0, /*desiredPresentTime*/ time + s2ns(1), false, + FrameTimelineInfo{}); // transaction that would not have gone on the pending thread if not // blocked TransactionInfo transactionB; - setupSingle(transactionB, flags, syncInputWindows, - /*desiredPresentTime*/ systemTime(), /*isAutoTimestamp*/ true, - FrameTimelineInfo{}); + setupSingle(transactionB, flags, /*desiredPresentTime*/ systemTime(), + /*isAutoTimestamp*/ true, FrameTimelineInfo{}); nsecs_t applicationSentTime = systemTime(); mFlinger.setTransactionState(transactionA.frameTimelineInfo, transactionA.states, @@ -226,8 +218,7 @@ public: // if this is an animation, this thread should be blocked for 5s // in setTransactionState waiting for transactionA to flush. Otherwise, // the transaction should be placed on the pending queue - if (flags & (ISurfaceComposer::eSynchronous) || - syncInputWindows) { + if (flags & ISurfaceComposer::eSynchronous) { EXPECT_GE(systemTime(), applicationSentTime + mFlinger.getAnimationTransactionTimeout()); } else { @@ -253,8 +244,8 @@ TEST_F(TransactionApplicationTest, Flush_RemovesFromQueue) { EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1); TransactionInfo transactionA; // transaction to go on pending queue - setupSingle(transactionA, /*flags*/ 0, /*syncInputWindows*/ false, - /*desiredPresentTime*/ s2ns(1), false, FrameTimelineInfo{}); + setupSingle(transactionA, /*flags*/ 0, /*desiredPresentTime*/ s2ns(1), false, + FrameTimelineInfo{}); mFlinger.setTransactionState(transactionA.frameTimelineInfo, transactionA.states, transactionA.displays, transactionA.flags, transactionA.applyToken, transactionA.inputWindowCommands, transactionA.desiredPresentTime, @@ -285,31 +276,23 @@ TEST_F(TransactionApplicationTest, Flush_RemovesFromQueue) { } TEST_F(TransactionApplicationTest, NotPlacedOnTransactionQueue_Synchronous) { - NotPlacedOnTransactionQueue(ISurfaceComposer::eSynchronous, /*syncInputWindows*/ false); + NotPlacedOnTransactionQueue(ISurfaceComposer::eSynchronous); } TEST_F(TransactionApplicationTest, NotPlacedOnTransactionQueue_SyncInputWindows) { - NotPlacedOnTransactionQueue(/*flags*/ 0, /*syncInputWindows*/ true); + NotPlacedOnTransactionQueue(/*flags*/ 0); } TEST_F(TransactionApplicationTest, PlaceOnTransactionQueue_Synchronous) { - PlaceOnTransactionQueue(ISurfaceComposer::eSynchronous, /*syncInputWindows*/ false); + PlaceOnTransactionQueue(ISurfaceComposer::eSynchronous); } TEST_F(TransactionApplicationTest, PlaceOnTransactionQueue_SyncInputWindows) { - PlaceOnTransactionQueue(/*flags*/ 0, /*syncInputWindows*/ true); + PlaceOnTransactionQueue(/*flags*/ 0); } TEST_F(TransactionApplicationTest, BlockWithPriorTransaction_Synchronous) { - BlockedByPriorTransaction(ISurfaceComposer::eSynchronous, /*syncInputWindows*/ false); -} - -TEST_F(TransactionApplicationTest, BlockWithPriorTransaction_Animation) { - BlockedByPriorTransaction(ISurfaceComposer::eSynchronous, /*syncInputWindows*/ false); -} - -TEST_F(TransactionApplicationTest, BlockWithPriorTransaction_SyncInputWindows) { - BlockedByPriorTransaction(/*flags*/ 0, /*syncInputWindows*/ true); + BlockedByPriorTransaction(ISurfaceComposer::eSynchronous); } TEST_F(TransactionApplicationTest, FromHandle) { @@ -359,13 +342,11 @@ public: const std::vector& states) { TransactionInfo transaction; const uint32_t kFlags = ISurfaceComposer::eSynchronous; - const bool kSyncInputWindows = false; const nsecs_t kDesiredPresentTime = systemTime(); const bool kIsAutoTimestamp = true; const auto kFrameTimelineInfo = FrameTimelineInfo{}; - setupSingle(transaction, kFlags, kSyncInputWindows, kDesiredPresentTime, kIsAutoTimestamp, - kFrameTimelineInfo); + setupSingle(transaction, kFlags, kDesiredPresentTime, kIsAutoTimestamp, kFrameTimelineInfo); transaction.applyToken = applyToken; for (const auto& state : states) { transaction.states.push_back(state); -- cgit v1.2.3-59-g8ed1b From 096227e9a48c96ed309ec369d8cbeb40015618f2 Mon Sep 17 00:00:00 2001 From: Andy Labrada Date: Wed, 15 Jun 2022 16:58:11 +0000 Subject: SurfaceFlinger: Remove usage of window types to implement policy Native side for a new API, setFrameRateDefault, where policy implementation logic is made using setFrameRateDefault instead of checking window types. To test the implementation of this API, SurfaceFlinger property use_content_detection_for_refresh_rate should be set to 1. Bug: 192291754 Test: atest LayerHistoryTest Test: added logs and verified status bar window gets no vote, wallpaper gets min vote and other windows get heuristic vote when use_content_detection_for_refresh_rate is set to 1 Change-Id: I736ac1bd82644b1fd8164f3be33f086934d27487 --- libs/gui/LayerState.cpp | 7 ++++ libs/gui/SurfaceComposerClient.cpp | 13 ++++++ libs/gui/include/gui/LayerState.h | 5 ++- libs/gui/include/gui/SurfaceComposerClient.h | 3 ++ libs/nativewindow/include/system/window.h | 5 +++ services/surfaceflinger/Layer.cpp | 16 ++++++++ services/surfaceflinger/Layer.h | 7 ++++ services/surfaceflinger/Scheduler/LayerHistory.cpp | 36 +++++++++++++++- services/surfaceflinger/Scheduler/LayerHistory.h | 6 ++- services/surfaceflinger/Scheduler/LayerInfo.h | 2 + services/surfaceflinger/Scheduler/Scheduler.cpp | 21 +++------- services/surfaceflinger/Scheduler/Scheduler.h | 1 + services/surfaceflinger/SurfaceFlinger.cpp | 8 ++++ .../tests/unittests/LayerHistoryTest.cpp | 48 ++++++++++++++++++++++ .../tests/unittests/mock/MockLayer.h | 7 +++- 15 files changed, 166 insertions(+), 19 deletions(-) (limited to 'libs/gui/LayerState.cpp') diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 7f0f6381e1..241c82f919 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -63,6 +63,7 @@ layer_state_t::layer_state_t() frameRate(0.0f), frameRateCompatibility(ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT), changeFrameRateStrategy(ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS), + defaultFrameRateCompatibility(ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT), fixedTransformHint(ui::Transform::ROT_INVALID), autoRefresh(false), isTrustedOverlay(false), @@ -137,6 +138,7 @@ status_t layer_state_t::write(Parcel& output) const SAFE_PARCEL(output.writeFloat, frameRate); SAFE_PARCEL(output.writeByte, frameRateCompatibility); SAFE_PARCEL(output.writeByte, changeFrameRateStrategy); + SAFE_PARCEL(output.writeByte, defaultFrameRateCompatibility); SAFE_PARCEL(output.writeUint32, fixedTransformHint); SAFE_PARCEL(output.writeBool, autoRefresh); SAFE_PARCEL(output.writeBool, dimmingEnabled); @@ -257,6 +259,7 @@ status_t layer_state_t::read(const Parcel& input) SAFE_PARCEL(input.readFloat, &frameRate); SAFE_PARCEL(input.readByte, &frameRateCompatibility); SAFE_PARCEL(input.readByte, &changeFrameRateStrategy); + SAFE_PARCEL(input.readByte, &defaultFrameRateCompatibility); SAFE_PARCEL(input.readUint32, &tmpUint32); fixedTransformHint = static_cast(tmpUint32); SAFE_PARCEL(input.readBool, &autoRefresh); @@ -573,6 +576,10 @@ void layer_state_t::merge(const layer_state_t& other) { borderWidth = other.borderWidth; borderColor = other.borderColor; } + if (other.what & eDefaultFrameRateCompatibilityChanged) { + what |= eDefaultFrameRateCompatibilityChanged; + defaultFrameRateCompatibility = other.defaultFrameRateCompatibility; + } if (other.what & eFrameRateSelectionPriority) { what |= eFrameRateSelectionPriority; frameRateSelectionPriority = other.frameRateSelectionPriority; diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 7191de8f7f..c459b3aa55 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1841,6 +1841,19 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrame return *this; } +SurfaceComposerClient::Transaction& +SurfaceComposerClient::Transaction::setDefaultFrameRateCompatibility(const sp& sc, + int8_t compatibility) { + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } + s->what |= layer_state_t::eDefaultFrameRateCompatibilityChanged; + s->defaultFrameRateCompatibility = compatibility; + return *this; +} + SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFixedTransformHint( const sp& sc, int32_t fixedTransformHint) { layer_state_t* s = getLayerState(sc); diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index 37a159512f..d9a4ae52d1 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -165,7 +165,7 @@ struct layer_state_t { eTransformToDisplayInverseChanged = 0x00080000, eCropChanged = 0x00100000, eBufferChanged = 0x00200000, - /* unused 0x00400000, */ + eDefaultFrameRateCompatibilityChanged = 0x00400000, eDataspaceChanged = 0x00800000, eHdrMetadataChanged = 0x01000000, eSurfaceDamageRegionChanged = 0x02000000, @@ -275,6 +275,9 @@ struct layer_state_t { int8_t frameRateCompatibility; int8_t changeFrameRateStrategy; + // Default frame rate compatibility used to set the layer refresh rate votetype. + int8_t defaultFrameRateCompatibility; + // Set by window manager indicating the layer and all its children are // in a different orientation than the display. The hint suggests that // the graphic producers should receive a transform hint as if the diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 9f036a6fb1..0dc521935c 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -583,6 +583,9 @@ public: Transaction& setFrameRate(const sp& sc, float frameRate, int8_t compatibility, int8_t changeFrameRateStrategy); + Transaction& setDefaultFrameRateCompatibility(const sp& sc, + int8_t compatibility); + // Set by window manager indicating the layer and all its children are // in a different orientation than the display. The hint suggests that // the graphic producers should receive a transform hint as if the diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h index a54af1fa62..79f49e1786 100644 --- a/libs/nativewindow/include/system/window.h +++ b/libs/nativewindow/include/system/window.h @@ -1034,6 +1034,11 @@ enum { * This surface is ignored while choosing the refresh rate. */ ANATIVEWINDOW_FRAME_RATE_NO_VOTE, + + /** + * This surface will vote for the minimum refresh rate. + */ + ANATIVEWINDOW_FRAME_RATE_MIN }; static inline int native_window_set_frame_rate(struct ANativeWindow* window, float frameRate, diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 80df3996ce..6e9dad1131 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -148,6 +148,7 @@ Layer::Layer(const LayerCreationArgs& args) mDrawingState.isTrustedOverlay = false; mDrawingState.dropInputMode = gui::DropInputMode::NONE; mDrawingState.dimmingEnabled = true; + mDrawingState.defaultFrameRateCompatibility = FrameRateCompatibility::Default; if (args.flags & ISurfaceComposerClient::eNoColorFill) { // Set an invalid color so there is no color fill. @@ -1101,6 +1102,19 @@ int32_t Layer::getFrameRateSelectionPriority() const { return Layer::PRIORITY_UNSET; } +bool Layer::setDefaultFrameRateCompatibility(FrameRateCompatibility compatibility) { + if (mDrawingState.defaultFrameRateCompatibility == compatibility) return false; + mDrawingState.defaultFrameRateCompatibility = compatibility; + mDrawingState.modified = true; + mFlinger->mScheduler->setDefaultFrameRateCompatibility(this); + setTransactionFlags(eTransactionNeeded); + return true; +} + +scheduler::LayerInfo::FrameRateCompatibility Layer::getDefaultFrameRateCompatibility() const { + return mDrawingState.defaultFrameRateCompatibility; +} + bool Layer::isLayerFocusedBasedOnPriority(int32_t priority) { return priority == PRIORITY_FOCUSED_WITH_MODE || priority == PRIORITY_FOCUSED_WITHOUT_MODE; }; @@ -2643,6 +2657,8 @@ Layer::FrameRateCompatibility Layer::FrameRate::convertCompatibility(int8_t comp return FrameRateCompatibility::ExactOrMultiple; case ANATIVEWINDOW_FRAME_RATE_EXACT: return FrameRateCompatibility::Exact; + case ANATIVEWINDOW_FRAME_RATE_MIN: + return FrameRateCompatibility::Min; case ANATIVEWINDOW_FRAME_RATE_NO_VOTE: return FrameRateCompatibility::NoVote; default: diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 911ab78956..fb9b663d8a 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -235,6 +235,9 @@ public: // Priority of the layer assigned by Window Manager. int32_t frameRateSelectionPriority; + // Default frame rate compatibility used to set the layer refresh rate votetype. + FrameRateCompatibility defaultFrameRateCompatibility; + FrameRate frameRate; // The combined frame rate of parents / children of this layer @@ -438,6 +441,7 @@ public: virtual bool setBackgroundColor(const half3& color, float alpha, ui::Dataspace dataspace); virtual bool setColorSpaceAgnostic(const bool agnostic); virtual bool setDimmingEnabled(const bool dimmingEnabled); + virtual bool setDefaultFrameRateCompatibility(FrameRateCompatibility compatibility); virtual bool setFrameRateSelectionPriority(int32_t priority); virtual bool setFixedTransformHint(ui::Transform::RotationFlags fixedTransformHint); virtual void setAutoRefresh(bool /* autoRefresh */) {} @@ -446,6 +450,9 @@ public: // If the variable is not set on the layer, it traverses up the tree to inherit the frame // rate priority from its parent. virtual int32_t getFrameRateSelectionPriority() const; + // + virtual FrameRateCompatibility getDefaultFrameRateCompatibility() const; + // virtual ui::Dataspace getDataSpace() const { return ui::Dataspace::UNKNOWN; } virtual sp getCompositionEngineLayerFE() const; diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp index 5f64efa3d1..ae111c3d45 100644 --- a/services/surfaceflinger/Scheduler/LayerHistory.cpp +++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp @@ -72,6 +72,20 @@ void trace(const LayerInfo& info, LayerHistory::LayerVoteType type, int fps) { ALOGD("%s: %s @ %d Hz", __FUNCTION__, info.getName().c_str(), fps); } + +LayerHistory::LayerVoteType getVoteType(LayerInfo::FrameRateCompatibility compatibility, + bool contentDetectionEnabled) { + LayerHistory::LayerVoteType voteType; + if (!contentDetectionEnabled || compatibility == LayerInfo::FrameRateCompatibility::NoVote) { + voteType = LayerHistory::LayerVoteType::NoVote; + } else if (compatibility == LayerInfo::FrameRateCompatibility::Min) { + voteType = LayerHistory::LayerVoteType::Min; + } else { + voteType = LayerHistory::LayerVoteType::Heuristic; + } + return voteType; +} + } // namespace LayerHistory::LayerHistory() @@ -81,10 +95,12 @@ LayerHistory::LayerHistory() LayerHistory::~LayerHistory() = default; -void LayerHistory::registerLayer(Layer* layer, LayerVoteType type) { +void LayerHistory::registerLayer(Layer* layer, bool contentDetectionEnabled) { std::lock_guard lock(mLock); LOG_ALWAYS_FATAL_IF(findLayer(layer->getSequence()).first != LayerStatus::NotFound, "%s already registered", layer->getName().c_str()); + LayerVoteType type = + getVoteType(layer->getDefaultFrameRateCompatibility(), contentDetectionEnabled); auto info = std::make_unique(layer->getName(), layer->getOwnerUid(), type); // The layer can be placed on either map, it is assumed that partitionLayers() will be called @@ -132,6 +148,22 @@ void LayerHistory::record(Layer* layer, nsecs_t presentTime, nsecs_t now, } } +void LayerHistory::setDefaultFrameRateCompatibility(Layer* layer, bool contentDetectionEnabled) { + std::lock_guard lock(mLock); + auto id = layer->getSequence(); + + auto [found, layerPair] = findLayer(id); + if (found == LayerStatus::NotFound) { + // Offscreen layer + ALOGV("%s: %s not registered", __func__, layer->getName().c_str()); + return; + } + + const auto& info = layerPair->second; + info->setDefaultLayerVote( + getVoteType(layer->getDefaultFrameRateCompatibility(), contentDetectionEnabled)); +} + auto LayerHistory::summarize(const RefreshRateConfigs& configs, nsecs_t now) -> Summary { Summary summary; @@ -203,6 +235,8 @@ void LayerHistory::partitionLayers(nsecs_t now) { switch (frameRate.type) { case Layer::FrameRateCompatibility::Default: return LayerVoteType::ExplicitDefault; + case Layer::FrameRateCompatibility::Min: + return LayerVoteType::Min; case Layer::FrameRateCompatibility::ExactOrMultiple: return LayerVoteType::ExplicitExactOrMultiple; case Layer::FrameRateCompatibility::NoVote: diff --git a/services/surfaceflinger/Scheduler/LayerHistory.h b/services/surfaceflinger/Scheduler/LayerHistory.h index 7b6096f7f3..12bec8dfc1 100644 --- a/services/surfaceflinger/Scheduler/LayerHistory.h +++ b/services/surfaceflinger/Scheduler/LayerHistory.h @@ -45,7 +45,7 @@ public: ~LayerHistory(); // Layers are unregistered when the weak reference expires. - void registerLayer(Layer*, LayerVoteType type); + void registerLayer(Layer*, bool contentDetectionEnabled); // Sets the display size. Client is responsible for synchronization. void setDisplayArea(uint32_t displayArea) { mDisplayArea = displayArea; } @@ -63,6 +63,10 @@ public: // Marks the layer as active, and records the given state to its history. void record(Layer*, nsecs_t presentTime, nsecs_t now, LayerUpdateType updateType); + // Updates the default frame rate compatibility which takes effect when the app + // does not set a preference for refresh rate. + void setDefaultFrameRateCompatibility(Layer*, bool contentDetectionEnabled); + using Summary = std::vector; // Rebuilds sets of active/inactive layers, and accumulates stats for active layers. diff --git a/services/surfaceflinger/Scheduler/LayerInfo.h b/services/surfaceflinger/Scheduler/LayerInfo.h index 8a3b0b97e4..28cb24a64f 100644 --- a/services/surfaceflinger/Scheduler/LayerInfo.h +++ b/services/surfaceflinger/Scheduler/LayerInfo.h @@ -74,6 +74,8 @@ public: enum class FrameRateCompatibility { Default, // Layer didn't specify any specific handling strategy + Min, // Layer needs the minimum frame rate. + Exact, // Layer needs the exact frame rate. ExactOrMultiple, // Layer needs the exact frame rate (or a multiple of it) to present the diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index bbf46678d5..3181a7f9c7 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -497,24 +497,10 @@ void Scheduler::addPresentFence(std::shared_ptr fence) { } void Scheduler::registerLayer(Layer* layer) { - using WindowType = gui::WindowInfo::Type; - - scheduler::LayerHistory::LayerVoteType voteType; - - if (!mFeatures.test(Feature::kContentDetection) || - layer->getWindowType() == WindowType::STATUS_BAR) { - voteType = scheduler::LayerHistory::LayerVoteType::NoVote; - } else if (layer->getWindowType() == WindowType::WALLPAPER) { - // Running Wallpaper at Min is considered as part of content detection. - voteType = scheduler::LayerHistory::LayerVoteType::Min; - } else { - voteType = scheduler::LayerHistory::LayerVoteType::Heuristic; - } - // If the content detection feature is off, we still keep the layer history, // since we use it for other features (like Frame Rate API), so layers // still need to be registered. - mLayerHistory.registerLayer(layer, voteType); + mLayerHistory.registerLayer(layer, mFeatures.test(Feature::kContentDetection)); } void Scheduler::deregisterLayer(Layer* layer) { @@ -535,6 +521,11 @@ void Scheduler::setModeChangePending(bool pending) { mLayerHistory.setModeChangePending(pending); } +void Scheduler::setDefaultFrameRateCompatibility(Layer* layer) { + mLayerHistory.setDefaultFrameRateCompatibility(layer, + mFeatures.test(Feature::kContentDetection)); +} + void Scheduler::chooseRefreshRateForContent() { const auto configs = holdRefreshRateConfigs(); if (!configs->canSwitch()) return; diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index 587a773433..7f76d1edc1 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -178,6 +178,7 @@ public: void recordLayerHistory(Layer*, nsecs_t presentTime, LayerHistory::LayerUpdateType updateType) EXCLUDES(mRefreshRateConfigsLock); void setModeChangePending(bool pending); + void setDefaultFrameRateCompatibility(Layer*); void deregisterLayer(Layer*); // Detects content using layer history, and selects a matching refresh rate. diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index aba7998b3c..c720c76f5f 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -4563,6 +4563,14 @@ uint32_t SurfaceFlinger::setClientStateLocked(const FrameTimelineInfo& frameTime if (what & layer_state_t::eShadowRadiusChanged) { if (layer->setShadowRadius(s.shadowRadius)) flags |= eTraversalNeeded; } + if (what & layer_state_t::eDefaultFrameRateCompatibilityChanged) { + const auto compatibility = + Layer::FrameRate::convertCompatibility(s.defaultFrameRateCompatibility); + + if (layer->setDefaultFrameRateCompatibility(compatibility)) { + flags |= eTraversalNeeded; + } + } if (what & layer_state_t::eFrameRateSelectionPriority) { if (layer->setFrameRateSelectionPriority(s.frameRateSelectionPriority)) { flags |= eTraversalNeeded; diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp index 17511cd615..972198cbdb 100644 --- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp @@ -141,6 +141,54 @@ protected: namespace { +TEST_F(LayerHistoryTest, singleLayerNoVoteDefaultCompatibility) { + const auto layer = createLayer(); + EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); + EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate())); + EXPECT_CALL(*layer, getDefaultFrameRateCompatibility()) + .WillOnce(Return(LayerInfo::FrameRateCompatibility::NoVote)); + + EXPECT_EQ(1, layerCount()); + EXPECT_EQ(0, activeLayerCount()); + + nsecs_t time = systemTime(); + + // No layers returned if no layers are active. + EXPECT_TRUE(summarizeLayerHistory(time).empty()); + EXPECT_EQ(0, activeLayerCount()); + + history().record(layer.get(), 0, time, LayerHistory::LayerUpdateType::Buffer); + history().setDefaultFrameRateCompatibility(layer.get(), true /* contentDetectionEnabled */); + + EXPECT_TRUE(summarizeLayerHistory(time).empty()); + EXPECT_EQ(1, activeLayerCount()); +} + +TEST_F(LayerHistoryTest, singleLayerMinVoteDefaultCompatibility) { + const auto layer = createLayer(); + EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); + EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate())); + EXPECT_CALL(*layer, getDefaultFrameRateCompatibility()) + .WillOnce(Return(LayerInfo::FrameRateCompatibility::Min)); + + EXPECT_EQ(1, layerCount()); + EXPECT_EQ(0, activeLayerCount()); + + nsecs_t time = systemTime(); + + EXPECT_TRUE(summarizeLayerHistory(time).empty()); + EXPECT_EQ(0, activeLayerCount()); + + history().record(layer.get(), 0, time, LayerHistory::LayerUpdateType::Buffer); + history().setDefaultFrameRateCompatibility(layer.get(), true /* contentDetectionEnabled */); + + auto summary = summarizeLayerHistory(time); + ASSERT_EQ(1, summarizeLayerHistory(time).size()); + + EXPECT_EQ(LayerHistory::LayerVoteType::Min, summarizeLayerHistory(time)[0].vote); + EXPECT_EQ(1, activeLayerCount()); +} + TEST_F(LayerHistoryTest, oneLayer) { const auto layer = createLayer(); EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); diff --git a/services/surfaceflinger/tests/unittests/mock/MockLayer.h b/services/surfaceflinger/tests/unittests/mock/MockLayer.h index 0840a2f77c..d086d79834 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockLayer.h +++ b/services/surfaceflinger/tests/unittests/mock/MockLayer.h @@ -25,7 +25,10 @@ namespace android::mock { class MockLayer : public Layer { public: MockLayer(SurfaceFlinger* flinger, std::string name) - : Layer(LayerCreationArgs(flinger, nullptr, std::move(name), 0, {})) {} + : Layer(LayerCreationArgs(flinger, nullptr, std::move(name), 0, {})) { + EXPECT_CALL(*this, getDefaultFrameRateCompatibility()) + .WillOnce(testing::Return(scheduler::LayerInfo::FrameRateCompatibility::Default)); + } explicit MockLayer(SurfaceFlinger* flinger) : MockLayer(flinger, "TestLayer") {} MOCK_CONST_METHOD0(getType, const char*()); @@ -33,6 +36,8 @@ public: MOCK_CONST_METHOD0(isVisible, bool()); MOCK_METHOD0(createClone, sp()); MOCK_CONST_METHOD0(getFrameRateForLayerTree, FrameRate()); + MOCK_CONST_METHOD0(getDefaultFrameRateCompatibility, + scheduler::LayerInfo::FrameRateCompatibility()); MOCK_CONST_METHOD0(getOwnerUid, uid_t()); MOCK_CONST_METHOD0(getDataSpace, ui::Dataspace()); }; -- cgit v1.2.3-59-g8ed1b From ea04b6f71e8be837f288a17c48c3f83f19f95a1e Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Fri, 19 Aug 2022 21:28:17 +0000 Subject: SF: Clean up layer state Remove unused layer states. Bug: 238781169 Test: presubmit Change-Id: I84917bed157a93ec9bfd16d168312ce27ff1765e --- cmds/surfacereplayer/replayer/Replayer.cpp | 1 - libs/gui/LayerState.cpp | 11 ---- libs/gui/SurfaceComposerClient.cpp | 15 ----- .../fuzzer/libgui_surfaceComposerClient_fuzzer.cpp | 2 - libs/gui/include/gui/LayerState.h | 4 +- libs/gui/include/gui/SurfaceComposerClient.h | 7 +-- services/surfaceflinger/BufferStateLayer.cpp | 10 ---- services/surfaceflinger/BufferStateLayer.h | 7 --- services/surfaceflinger/Layer.cpp | 33 ++--------- services/surfaceflinger/Layer.h | 67 +--------------------- services/surfaceflinger/SurfaceFlinger.cpp | 5 -- services/surfaceflinger/SurfaceInterceptor.cpp | 7 --- .../Tracing/TransactionProtoParser.cpp | 9 +-- .../surfaceflinger/layerproto/transactions.proto | 2 +- .../surfaceflinger/tests/LayerTransactionTest.h | 2 +- .../tests/SurfaceInterceptor_test.cpp | 16 ++---- .../tests/unittests/CompositionTest.cpp | 2 - 17 files changed, 18 insertions(+), 182 deletions(-) (limited to 'libs/gui/LayerState.cpp') diff --git a/cmds/surfacereplayer/replayer/Replayer.cpp b/cmds/surfacereplayer/replayer/Replayer.cpp index 3f7c7d6a7b..44235ccdef 100644 --- a/cmds/surfacereplayer/replayer/Replayer.cpp +++ b/cmds/surfacereplayer/replayer/Replayer.cpp @@ -464,7 +464,6 @@ void Replayer::setPosition(SurfaceComposerClient::Transaction& t, void Replayer::setSize(SurfaceComposerClient::Transaction& t, layer_id id, const SizeChange& sc) { ALOGV("Layer %d: Setting Size -- w=%u, h=%u", id, sc.w(), sc.h()); - t.setSize(mLayers[id], sc.w(), sc.h()); } void Replayer::setLayer(SurfaceComposerClient::Transaction& t, diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index bb660854c8..4d5978ccf7 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -40,8 +40,6 @@ layer_state_t::layer_state_t() x(0), y(0), z(0), - w(0), - h(0), alpha(0), flags(0), mask(0), @@ -84,8 +82,6 @@ status_t layer_state_t::write(Parcel& output) const SAFE_PARCEL(output.writeFloat, x); SAFE_PARCEL(output.writeFloat, y); SAFE_PARCEL(output.writeInt32, z); - SAFE_PARCEL(output.writeUint32, w); - SAFE_PARCEL(output.writeUint32, h); SAFE_PARCEL(output.writeUint32, layerStack.id); SAFE_PARCEL(output.writeFloat, alpha); SAFE_PARCEL(output.writeUint32, flags); @@ -180,8 +176,6 @@ status_t layer_state_t::read(const Parcel& input) SAFE_PARCEL(input.readFloat, &x); SAFE_PARCEL(input.readFloat, &y); SAFE_PARCEL(input.readInt32, &z); - SAFE_PARCEL(input.readUint32, &w); - SAFE_PARCEL(input.readUint32, &h); SAFE_PARCEL(input.readUint32, &layerStack.id); SAFE_PARCEL(input.readFloat, &alpha); @@ -457,11 +451,6 @@ void layer_state_t::merge(const layer_state_t& other) { what &= ~eRelativeLayerChanged; z = other.z; } - if (other.what & eSizeChanged) { - what |= eSizeChanged; - w = other.w; - h = other.h; - } if (other.what & eAlphaChanged) { what |= eAlphaChanged; alpha = other.alpha; diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index e8aaf629b3..8e29c42f88 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1165,21 +1165,6 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::hide( return setFlags(sc, layer_state_t::eLayerHidden, layer_state_t::eLayerHidden); } -SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setSize( - const sp& sc, uint32_t w, uint32_t h) { - layer_state_t* s = getLayerState(sc); - if (!s) { - mStatus = BAD_INDEX; - return *this; - } - s->what |= layer_state_t::eSizeChanged; - s->w = w; - s->h = h; - - registerSurfaceControlForCallback(sc); - return *this; -} - SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setLayer( const sp& sc, int32_t z) { layer_state_t* s = getLayerState(sc); diff --git a/libs/gui/fuzzer/libgui_surfaceComposerClient_fuzzer.cpp b/libs/gui/fuzzer/libgui_surfaceComposerClient_fuzzer.cpp index 05564e093a..48c90c5e8f 100644 --- a/libs/gui/fuzzer/libgui_surfaceComposerClient_fuzzer.cpp +++ b/libs/gui/fuzzer/libgui_surfaceComposerClient_fuzzer.cpp @@ -182,8 +182,6 @@ void SurfaceComposerClientFuzzer::invokeSurfaceComposerTransaction() { sp surface = makeSurfaceControl(); SurfaceComposerClient::Transaction transaction; - transaction.setSize(surface, mFdp.ConsumeIntegral(), - mFdp.ConsumeIntegral()); int32_t layer = mFdp.ConsumeIntegral(); transaction.setLayer(surface, layer); diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index 759fcc6c53..3c7b16266d 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -148,7 +148,7 @@ struct layer_state_t { enum { ePositionChanged = 0x00000001, eLayerChanged = 0x00000002, - eSizeChanged = 0x00000004, + // unused = 0x00000004, eAlphaChanged = 0x00000008, eMatrixChanged = 0x00000010, eTransparentRegionChanged = 0x00000020, @@ -217,8 +217,6 @@ struct layer_state_t { float x; float y; int32_t z; - uint32_t w; - uint32_t h; ui::LayerStack layerStack = ui::DEFAULT_LAYER_STACK; float alpha; uint32_t flags; diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 20c38d8012..533362e1fe 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -468,10 +468,9 @@ public: Transaction& merge(Transaction&& other); Transaction& show(const sp& sc); Transaction& hide(const sp& sc); - Transaction& setPosition(const sp& sc, - float x, float y); - Transaction& setSize(const sp& sc, - uint32_t w, uint32_t h); + Transaction& setPosition(const sp& sc, float x, float y); + // b/243180033 remove once functions are not called from vendor code + Transaction& setSize(const sp&, uint32_t, uint32_t) { return *this; } Transaction& setLayer(const sp& sc, int32_t z); diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index cce6ad7fe0..0cedfc8138 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -531,8 +531,6 @@ bool BufferStateLayer::setBuffer(std::shared_ptr& FrameTracer::FrameEvent::QUEUE); } - mDrawingState.width = mDrawingState.buffer->getWidth(); - mDrawingState.height = mDrawingState.buffer->getHeight(); mDrawingState.releaseBufferEndpoint = bufferData.releaseBufferEndpoint; return true; } @@ -622,14 +620,6 @@ bool BufferStateLayer::setTransactionCompletedListeners( return willPresent; } -bool BufferStateLayer::setTransparentRegionHint(const Region& transparent) { - mDrawingState.sequence++; - mDrawingState.transparentRegionHint = transparent; - mDrawingState.modified = true; - setTransactionFlags(eTransactionNeeded); - return true; -} - Rect BufferStateLayer::getBufferSize(const State& /*s*/) const { // for buffer state layers we use the display frame size as the buffer size. diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h index a0f13e21d4..a0a52bfcd3 100644 --- a/services/surfaceflinger/BufferStateLayer.h +++ b/services/surfaceflinger/BufferStateLayer.h @@ -116,9 +116,6 @@ public: void releasePendingBuffer(nsecs_t dequeueReadyTime) override; - Region getActiveTransparentRegion(const Layer::State& s) const override { - return s.transparentRegionHint; - } Rect getCrop(const Layer::State& s) const; bool setTransform(uint32_t transform) override; @@ -137,10 +134,6 @@ public: bool setPosition(float /*x*/, float /*y*/) override; bool setMatrix(const layer_state_t::matrix22_t& /*matrix*/); - // Override to ignore legacy layer state properties that are not used by BufferStateLayer - bool setSize(uint32_t /*w*/, uint32_t /*h*/) override { return false; } - bool setTransparentRegionHint(const Region& transparent) override; - // BufferStateLayers can return Rect::INVALID_RECT if the layer does not have a display frame // and its parent layer is not bounded Rect getBufferSize(const State& s) const override; diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index dfff8fe8ee..8a401eb597 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -111,16 +111,11 @@ Layer::Layer(const LayerCreationArgs& args) sSequence = *args.sequence + 1; } mDrawingState.flags = layerFlags; - mDrawingState.active_legacy.transform.set(0, 0); mDrawingState.crop.makeInvalid(); - mDrawingState.requestedCrop = mDrawingState.crop; mDrawingState.z = 0; mDrawingState.color.a = 1.0f; mDrawingState.layerStack = ui::DEFAULT_LAYER_STACK; mDrawingState.sequence = 0; - mDrawingState.requested_legacy = mDrawingState.active_legacy; - mDrawingState.width = UINT32_MAX; - mDrawingState.height = UINT32_MAX; mDrawingState.transform.set(0, 0); mDrawingState.frameNumber = 0; mDrawingState.bufferTransform = 0; @@ -875,20 +870,6 @@ bool Layer::isTrustedOverlay() const { return (p != nullptr) && p->isTrustedOverlay(); } -bool Layer::setSize(uint32_t w, uint32_t h) { - if (mDrawingState.requested_legacy.w == w && mDrawingState.requested_legacy.h == h) - return false; - mDrawingState.requested_legacy.w = w; - mDrawingState.requested_legacy.h = h; - mDrawingState.modified = true; - setTransactionFlags(eTransactionNeeded); - - // record the new size, from this point on, when the client request - // a buffer, it'll get the new size. - setDefaultBufferSize(mDrawingState.requested_legacy.w, mDrawingState.requested_legacy.h); - return true; -} - bool Layer::setAlpha(float alpha) { if (mDrawingState.color.a == alpha) return false; mDrawingState.sequence++; @@ -978,7 +959,8 @@ bool Layer::setMatrix(const layer_state_t::matrix22_t& matrix) { } bool Layer::setTransparentRegionHint(const Region& transparent) { - mDrawingState.requestedTransparentRegion_legacy = transparent; + mDrawingState.sequence++; + mDrawingState.transparentRegionHint = transparent; mDrawingState.modified = true; setTransactionFlags(eTransactionNeeded); return true; @@ -1007,9 +989,8 @@ bool Layer::setFlags(uint32_t flags, uint32_t mask) { } bool Layer::setCrop(const Rect& crop) { - if (mDrawingState.requestedCrop == crop) return false; + if (mDrawingState.crop == crop) return false; mDrawingState.sequence++; - mDrawingState.requestedCrop = crop; mDrawingState.crop = crop; mDrawingState.modified = true; @@ -1433,7 +1414,6 @@ gui::LayerDebugInfo Layer::getLayerDebugInfo(const DisplayDevice* display) const sp parent = mDrawingParent.promote(); info.mParentName = parent ? parent->getName() : "none"s; info.mType = getType(); - info.mTransparentRegion = ds.activeTransparentRegion_legacy; info.mVisibleRegion = getVisibleRegion(display); info.mSurfaceDamageRegion = surfaceDamageRegion; @@ -1441,8 +1421,6 @@ gui::LayerDebugInfo Layer::getLayerDebugInfo(const DisplayDevice* display) const info.mX = ds.transform.tx(); info.mY = ds.transform.ty(); info.mZ = ds.z; - info.mWidth = ds.width; - info.mHeight = ds.height; info.mCrop = ds.crop; info.mColor = ds.color; info.mFlags = ds.flags; @@ -2141,7 +2119,7 @@ void Layer::writeToProtoCommonState(LayerProto* layerInfo, LayerVector::StateSet } } - LayerProtoHelper::writeToProto(state.activeTransparentRegion_legacy, + LayerProtoHelper::writeToProto(state.transparentRegionHint, [&]() { return layerInfo->mutable_transparent_region(); }); layerInfo->set_layer_stack(getLayerStack().id); @@ -2151,9 +2129,6 @@ void Layer::writeToProtoCommonState(LayerProto* layerInfo, LayerVector::StateSet return layerInfo->mutable_requested_position(); }); - LayerProtoHelper::writeSizeToProto(state.width, state.height, - [&]() { return layerInfo->mutable_size(); }); - LayerProtoHelper::writeToProto(state.crop, [&]() { return layerInfo->mutable_crop(); }); layerInfo->set_is_opaque(isOpaque(state)); diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 6e83b235d4..b05a4a04e5 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -150,40 +150,23 @@ public: using FrameRateCompatibility = scheduler::LayerInfo::FrameRateCompatibility; struct State { - Geometry active_legacy; - Geometry requested_legacy; int32_t z; - ui::LayerStack layerStack; - uint32_t flags; - uint8_t reserved[2]; int32_t sequence; // changes when visible regions can change bool modified; - // Crop is expressed in layer space coordinate. Rect crop; - Rect requestedCrop; - - // the transparentRegion hint is a bit special, it's latched only - // when we receive a buffer -- this is because it's "content" - // dependent. - Region activeTransparentRegion_legacy; - Region requestedTransparentRegion_legacy; - LayerMetadata metadata; - // If non-null, a Surface this Surface's Z-order is interpreted relative to. wp zOrderRelativeOf; bool isRelativeOf{false}; // A list of surfaces whose Z-order is interpreted relative to ours. SortedVector> zOrderRelatives; - half4 color; float cornerRadius; int backgroundBlurRadius; - gui::WindowInfo inputInfo; wp touchableRegionCrop; @@ -192,15 +175,10 @@ public: // The fields below this point are only used by BufferStateLayer uint64_t frameNumber; - uint32_t width; - uint32_t height; ui::Transform transform; - uint32_t bufferTransform; bool transformToDisplayInverse; - Region transparentRegionHint; - std::shared_ptr buffer; client_cache_t clientCacheId; sp acquireFence; @@ -208,11 +186,9 @@ public: HdrMetadata hdrMetadata; Region surfaceDamageRegion; int32_t api; - sp sidebandStream; mat4 colorTransform; bool hasColorTransform; - // pointer to background color layer that, if set, appears below the buffer state layer // and the buffer state layer's children. Z order will be set to // INT_MIN @@ -237,7 +213,6 @@ public: // Default frame rate compatibility used to set the layer refresh rate votetype. FrameRateCompatibility defaultFrameRateCompatibility; - FrameRate frameRate; // The combined frame rate of parents / children of this layer @@ -257,7 +232,6 @@ public: // When the transaction was posted nsecs_t postTime; - sp releaseBufferListener; // SurfaceFrame that tracks the timeline of Transactions that contain a Buffer. Only one // such SurfaceFrame exists because only one buffer can be presented on the layer per vsync. @@ -278,16 +252,11 @@ public: // Whether or not this layer is a trusted overlay for input bool isTrustedOverlay; - Rect bufferCrop; Rect destinationFrame; - sp releaseBufferEndpoint; - gui::DropInputMode dropInputMode; - bool autoRefresh = false; - bool dimmingEnabled = true; }; @@ -345,32 +314,6 @@ public: virtual sp createClone() = 0; - // Geometry setting functions. - // - // The following group of functions are used to specify the layers - // bounds, and the mapping of the texture on to those bounds. According - // to various settings changes to them may apply immediately, or be delayed until - // a pending resize is completed by the producer submitting a buffer. For example - // if we were to change the buffer size, and update the matrix ahead of the - // new buffer arriving, then we would be stretching the buffer to a different - // aspect before and after the buffer arriving, which probably isn't what we wanted. - // - // The first set of geometry functions are controlled by the scaling mode, described - // in window.h. The scaling mode may be set by the client, as it submits buffers. - // - // Put simply, if our scaling mode is SCALING_MODE_FREEZE, then - // matrix updates will not be applied while a resize is pending - // and the size and transform will remain in their previous state - // until a new buffer is submitted. If the scaling mode is another value - // then the old-buffer will immediately be scaled to the pending size - // and the new matrix will be immediately applied following this scaling - // transformation. - - // Set the default buffer size for the assosciated Producer, in pixels. This is - // also the rendered size of the layer prior to any transformations. Parent - // or local matrix transformations will not affect the size of the buffer, - // but may affect it's on-screen size or clipping. - virtual bool setSize(uint32_t w, uint32_t h); // Set a 2x2 transformation matrix on the layer. This transform // will be applied after parent transforms, but before any final // producer specified transform. @@ -407,7 +350,7 @@ public: // is specified in pixels. virtual bool setBackgroundBlurRadius(int backgroundBlurRadius); virtual bool setBlurRegions(const std::vector& effectRegions); - virtual bool setTransparentRegionHint(const Region& transparent); + bool setTransparentRegionHint(const Region& transparent); virtual bool setTrustedOverlay(bool); virtual bool setFlags(uint32_t flags, uint32_t mask); virtual bool setLayerStack(ui::LayerStack); @@ -500,11 +443,9 @@ public: // to avoid grabbing the lock again to avoid deadlock virtual bool isCreatedFromMainThread() const { return false; } - uint32_t getActiveWidth(const Layer::State& s) const { return s.width; } - uint32_t getActiveHeight(const Layer::State& s) const { return s.height; } ui::Transform getActiveTransform(const Layer::State& s) const { return s.transform; } - virtual Region getActiveTransparentRegion(const Layer::State& s) const { - return s.activeTransparentRegion_legacy; + Region getActiveTransparentRegion(const Layer::State& s) const { + return s.transparentRegionHint; } virtual Rect getCrop(const Layer::State& s) const { return s.crop; } virtual bool needsFiltering(const DisplayDevice*) const { return false; } @@ -524,8 +465,6 @@ public: virtual void updateCloneBufferInfo(){}; - virtual void setDefaultBufferSize(uint32_t /*w*/, uint32_t /*h*/) {} - virtual bool isHdrY410() const { return false; } /* diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 6b4cfa1249..e8d286295d 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -4254,11 +4254,6 @@ uint32_t SurfaceFlinger::setClientStateLocked(const FrameTimelineInfo& frameTime } } } - if (what & layer_state_t::eSizeChanged) { - if (layer->setSize(s.w, s.h)) { - flags |= eTraversalNeeded; - } - } if (what & layer_state_t::eAlphaChanged) { if (layer->setAlpha(s.alpha)) flags |= eTraversalNeeded; diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp index 66691c2a31..6797aa697b 100644 --- a/services/surfaceflinger/SurfaceInterceptor.cpp +++ b/services/surfaceflinger/SurfaceInterceptor.cpp @@ -135,8 +135,6 @@ void SurfaceInterceptor::addInitialSurfaceStateLocked(Increment* increment, layer->mDrawingState.transform.ty()); addDepthLocked(transaction, layerId, layer->mDrawingState.z); addAlphaLocked(transaction, layerId, layer->mDrawingState.color.a); - addTransparentRegionLocked(transaction, layerId, - layer->mDrawingState.activeTransparentRegion_legacy); addLayerStackLocked(transaction, layerId, layer->mDrawingState.layerStack); addCropLocked(transaction, layerId, layer->mDrawingState.crop); addCornerRadiusLocked(transaction, layerId, layer->mDrawingState.cornerRadius); @@ -420,9 +418,6 @@ void SurfaceInterceptor::addSurfaceChangesLocked(Transaction* transaction, if (state.what & layer_state_t::eLayerChanged) { addDepthLocked(transaction, layerId, state.z); } - if (state.what & layer_state_t::eSizeChanged) { - addSizeLocked(transaction, layerId, state.w, state.h); - } if (state.what & layer_state_t::eAlphaChanged) { addAlphaLocked(transaction, layerId, state.alpha); } @@ -522,8 +517,6 @@ void SurfaceInterceptor::addSurfaceCreationLocked(Increment* increment, SurfaceCreation* creation(increment->mutable_surface_creation()); creation->set_id(getLayerId(layer)); creation->set_name(layer->getName()); - creation->set_w(layer->mDrawingState.active_legacy.w); - creation->set_h(layer->mDrawingState.active_legacy.h); } void SurfaceInterceptor::addSurfaceDeletionLocked(Increment* increment, diff --git a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp index 77dec6f7fb..dcc529ecc5 100644 --- a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp +++ b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp @@ -88,10 +88,7 @@ proto::LayerState TransactionProtoParser::toProto(const layer_state_t& layer) { if (layer.what & layer_state_t::eLayerChanged) { proto.set_z(layer.z); } - if (layer.what & layer_state_t::eSizeChanged) { - proto.set_w(layer.w); - proto.set_h(layer.h); - } + if (layer.what & layer_state_t::eLayerStackChanged) { proto.set_layer_stack(layer.layerStack.id); } @@ -376,10 +373,6 @@ void TransactionProtoParser::fromProto(const proto::LayerState& proto, layer_sta if (proto.what() & layer_state_t::eLayerChanged) { layer.z = proto.z(); } - if (proto.what() & layer_state_t::eSizeChanged) { - layer.w = proto.w(); - layer.h = proto.h(); - } if (proto.what() & layer_state_t::eLayerStackChanged) { layer.layerStack.id = proto.layer_stack(); } diff --git a/services/surfaceflinger/layerproto/transactions.proto b/services/surfaceflinger/layerproto/transactions.proto index 49487ee550..b687abc918 100644 --- a/services/surfaceflinger/layerproto/transactions.proto +++ b/services/surfaceflinger/layerproto/transactions.proto @@ -82,7 +82,7 @@ message LayerState { eChangesLsbNone = 0; ePositionChanged = 0x00000001; eLayerChanged = 0x00000002; - eSizeChanged = 0x00000004; + // unused = 0x00000004; eAlphaChanged = 0x00000008; eMatrixChanged = 0x00000010; diff --git a/services/surfaceflinger/tests/LayerTransactionTest.h b/services/surfaceflinger/tests/LayerTransactionTest.h index 4b9160580f..0e8f3dd1d4 100644 --- a/services/surfaceflinger/tests/LayerTransactionTest.h +++ b/services/surfaceflinger/tests/LayerTransactionTest.h @@ -233,7 +233,7 @@ protected: Rect(halfW, halfH, bufferWidth, bufferHeight), bottomRight); - Transaction().setBuffer(layer, buffer).setSize(layer, bufferWidth, bufferHeight).apply(); + Transaction().setBuffer(layer, buffer).apply(); } std::unique_ptr screenshot() { diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp index 8dcd013985..d79e59211b 100644 --- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp +++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp @@ -140,6 +140,7 @@ protected: mComposerClient = sp::make(); ASSERT_EQ(NO_ERROR, mComposerClient->initCheck()); + GTEST_SKIP(); } void TearDown() override { @@ -342,9 +343,7 @@ void SurfaceInterceptorTest::positionUpdate(Transaction& t) { t.setPosition(mBGSurfaceControl, POSITION_UPDATE, POSITION_UPDATE); } -void SurfaceInterceptorTest::sizeUpdate(Transaction& t) { - t.setSize(mBGSurfaceControl, SIZE_UPDATE, SIZE_UPDATE); -} +void SurfaceInterceptorTest::sizeUpdate(Transaction&) {} void SurfaceInterceptorTest::alphaUpdate(Transaction& t) { t.setAlpha(mBGSurfaceControl, ALPHA_UPDATE); @@ -472,15 +471,8 @@ bool SurfaceInterceptorTest::positionUpdateFound(const SurfaceChange& change, bo return foundPosition; } -bool SurfaceInterceptorTest::sizeUpdateFound(const SurfaceChange& change, bool foundSize) { - bool hasWidth(change.size().h() == SIZE_UPDATE); - bool hasHeight(change.size().w() == SIZE_UPDATE); - if (hasWidth && hasHeight && !foundSize) { - foundSize = true; - } else if (hasWidth && hasHeight && foundSize) { - [] () { FAIL(); }(); - } - return foundSize; +bool SurfaceInterceptorTest::sizeUpdateFound(const SurfaceChange&, bool) { + return true; } bool SurfaceInterceptorTest::alphaUpdateFound(const SurfaceChange& change, bool foundAlpha) { diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index 2571e3a0ff..0666561642 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -828,8 +828,6 @@ struct BaseLayerVariant { static void initLayerDrawingStateAndComputeBounds(CompositionTest* test, sp layer) { auto& layerDrawingState = test->mFlinger.mutableLayerDrawingState(layer); layerDrawingState.layerStack = LAYER_STACK; - layerDrawingState.width = 100; - layerDrawingState.height = 100; layerDrawingState.color = half4(LayerProperties::COLOR[0], LayerProperties::COLOR[1], LayerProperties::COLOR[2], LayerProperties::COLOR[3]); layer->computeBounds(FloatRect(0, 0, 100, 100), ui::Transform(), 0.f /* shadowRadius */); -- cgit v1.2.3-59-g8ed1b From 59f6d2df6cbc895651eb2628c9f98505ed9de8bf Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Wed, 5 Oct 2022 16:59:56 -0700 Subject: SF: Add TransactionHandler - migrate transaction queueing and flushing into a new class and remove dependencies from other components. - Add a filter interface for other components to participate in transactionready logic. Test: presubmit Bug: 238781169 Change-Id: Ia4da386cd72058126f6f765adafb9cb4d15b1d2b --- libs/gui/LayerState.cpp | 2 +- libs/gui/include/gui/fake/BufferData.h | 51 ++++ services/surfaceflinger/Android.bp | 1 + services/surfaceflinger/Layer.h | 4 +- services/surfaceflinger/SurfaceFlinger.cpp | 332 +++++++-------------- services/surfaceflinger/SurfaceFlinger.h | 41 +-- .../Tracing/TransactionProtoParser.h | 32 +- services/surfaceflinger/TransactionHandler.cpp | 188 ++++++++++++ services/surfaceflinger/TransactionHandler.h | 74 +++++ services/surfaceflinger/TransactionState.h | 9 + .../fuzzer/surfaceflinger_fuzzers_utils.h | 6 +- .../tests/unittests/TestableSurfaceFlinger.h | 9 +- .../tests/unittests/TransactionApplicationTest.cpp | 67 ++--- 13 files changed, 490 insertions(+), 326 deletions(-) create mode 100644 libs/gui/include/gui/fake/BufferData.h create mode 100644 services/surfaceflinger/TransactionHandler.cpp create mode 100644 services/surfaceflinger/TransactionHandler.h (limited to 'libs/gui/LayerState.cpp') diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 4d5978ccf7..2759c58fb1 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -634,7 +634,7 @@ bool layer_state_t::hasBufferChanges() const { } bool layer_state_t::hasValidBuffer() const { - return bufferData && (bufferData->buffer || bufferData->cachedBuffer.isValid()); + return bufferData && (bufferData->hasBuffer() || bufferData->cachedBuffer.isValid()); } status_t layer_state_t::matrix22_t::write(Parcel& output) const { diff --git a/libs/gui/include/gui/fake/BufferData.h b/libs/gui/include/gui/fake/BufferData.h new file mode 100644 index 0000000000..725d11c313 --- /dev/null +++ b/libs/gui/include/gui/fake/BufferData.h @@ -0,0 +1,51 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +namespace android::fake { + +// Class which exposes buffer properties from BufferData without holding on to an actual buffer +class BufferData : public android::BufferData { +public: + BufferData(uint64_t bufferId, uint32_t width, uint32_t height, int32_t pixelFormat, + uint64_t outUsage) + : mBufferId(bufferId), + mWidth(width), + mHeight(height), + mPixelFormat(pixelFormat), + mOutUsage(outUsage) {} + bool hasBuffer() const override { return mBufferId != 0; } + bool hasSameBuffer(const android::BufferData& other) const override { + return getId() == other.getId() && frameNumber == other.frameNumber; + } + uint32_t getWidth() const override { return mWidth; } + uint32_t getHeight() const override { return mHeight; } + uint64_t getId() const override { return mBufferId; } + PixelFormat getPixelFormat() const override { return mPixelFormat; } + uint64_t getUsage() const override { return mOutUsage; } + +private: + uint64_t mBufferId; + uint32_t mWidth; + uint32_t mHeight; + int32_t mPixelFormat; + uint64_t mOutUsage; +}; + +} // namespace android::fake diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index b911ae75d4..809c80be0d 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -194,6 +194,7 @@ filegroup { "Tracing/TransactionTracing.cpp", "Tracing/TransactionProtoParser.cpp", "TransactionCallbackInvoker.cpp", + "TransactionHandler.cpp", "TunnelModeEnabledReporter.cpp", ], } diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 4ff86e5dd6..418056c22c 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -881,7 +881,9 @@ public: bool mPendingHWCDestroy{false}; - bool backpressureEnabled() { return mDrawingState.flags & layer_state_t::eEnableBackpressure; } + bool backpressureEnabled() const { + return mDrawingState.flags & layer_state_t::eEnableBackpressure; + } bool setStretchEffect(const StretchEffect& effect); StretchEffect getStretchEffect() const; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 3419721865..002a637899 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -129,14 +129,11 @@ #include "LayerVector.h" #include "MutexUtils.h" #include "NativeWindowSurface.h" -#include "RefreshRateOverlay.h" #include "RegionSamplingThread.h" -#include "Scheduler/DispSyncSource.h" #include "Scheduler/EventThread.h" #include "Scheduler/LayerHistory.h" #include "Scheduler/Scheduler.h" #include "Scheduler/VsyncConfiguration.h" -#include "Scheduler/VsyncController.h" #include "StartPropertySetThread.h" #include "SurfaceFlingerProperties.h" #include "SurfaceInterceptor.h" @@ -775,6 +772,7 @@ chooseRenderEngineTypeViaSysProp() { void SurfaceFlinger::init() FTL_FAKE_GUARD(kMainThreadContext) { ALOGI( "SurfaceFlinger's main thread ready to run. " "Initializing graphics H/W..."); + addTransactionReadyFilters(); Mutex::Autolock lock(mStateLock); // Get a RenderEngine for the given display / config (can't fail) @@ -3691,122 +3689,117 @@ void SurfaceFlinger::setTransactionFlags(uint32_t mask, TransactionSchedule sche } } -int SurfaceFlinger::flushPendingTransactionQueues( - std::vector& transactions, - std::unordered_map, uint64_t, SpHash>& bufferLayersReadyToPresent, - bool tryApplyUnsignaled) { - std::unordered_set, SpHash> applyTokensWithUnsignaledTransactions; - int transactionsPendingBarrier = 0; - auto it = mPendingTransactionQueues.begin(); - while (it != mPendingTransactionQueues.end()) { - auto& [applyToken, transactionQueue] = *it; - while (!transactionQueue.empty()) { - // if we are in LatchUnsignaledConfig::AutoSingleLayer - // then we should have only one applyToken for processing. - // so we can stop further transactions on this applyToken. - if (enableLatchUnsignaledConfig == LatchUnsignaledConfig::AutoSingleLayer && - !applyTokensWithUnsignaledTransactions.empty()) { - ATRACE_NAME("stopTransactionProcessing"); - break; - } +TransactionHandler::TransactionReadiness SurfaceFlinger::transactionReadyTimelineCheck( + const TransactionHandler::TransactionFlushState& flushState) { + using TransactionReadiness = TransactionHandler::TransactionReadiness; + const auto& transaction = *flushState.transaction; + ATRACE_FORMAT("transactionIsReadyToBeApplied vsyncId: %" PRId64, + transaction.frameTimelineInfo.vsyncId); + TimePoint desiredPresentTime = TimePoint::fromNs(transaction.desiredPresentTime); + // Do not present if the desiredPresentTime has not passed unless it is more than + // one second in the future. We ignore timestamps more than 1 second in the future + // for stability reasons. + if (!transaction.isAutoTimestamp && desiredPresentTime >= mExpectedPresentTime && + desiredPresentTime < mExpectedPresentTime + 1s) { + ATRACE_NAME("not current"); + return TransactionReadiness::NotReady; + } - auto& transaction = transactionQueue.front(); - const auto ready = - transactionIsReadyToBeApplied(transaction, transaction.frameTimelineInfo, - transaction.isAutoTimestamp, - TimePoint::fromNs(transaction.desiredPresentTime), - transaction.originUid, transaction.states, - bufferLayersReadyToPresent, transactions.size(), - tryApplyUnsignaled); - ATRACE_INT("TransactionReadiness", static_cast(ready)); - if (ready == TransactionReadiness::NotReady) { - setTransactionFlags(eTransactionFlushNeeded); - break; - } - if (ready == TransactionReadiness::NotReadyBarrier) { - transactionsPendingBarrier++; - setTransactionFlags(eTransactionFlushNeeded); - break; + if (!mScheduler->isVsyncValid(mExpectedPresentTime, transaction.originUid)) { + ATRACE_NAME("!isVsyncValid"); + return TransactionReadiness::NotReady; + } + + // If the client didn't specify desiredPresentTime, use the vsyncId to determine the + // expected present time of this transaction. + if (transaction.isAutoTimestamp && + frameIsEarly(mExpectedPresentTime, VsyncId{transaction.frameTimelineInfo.vsyncId})) { + ATRACE_NAME("frameIsEarly"); + return TransactionReadiness::NotReady; + } + return TransactionReadiness::Ready; +} + +TransactionHandler::TransactionReadiness SurfaceFlinger::transactionReadyBufferCheck( + const TransactionHandler::TransactionFlushState& flushState) { + using TransactionReadiness = TransactionHandler::TransactionReadiness; + auto ready = TransactionReadiness::Ready; + flushState.transaction->traverseStatesWithBuffersWhileTrue([&](const layer_state_t& s) -> bool { + sp layer = Layer::fromHandle(s.surface).promote(); + const auto& transaction = *flushState.transaction; + // check for barrier frames + if (s.bufferData->hasBarrier && + ((layer->getDrawingState().frameNumber) < s.bufferData->barrierFrameNumber)) { + const bool willApplyBarrierFrame = + flushState.bufferLayersReadyToPresent.contains(s.surface.get()) && + (flushState.bufferLayersReadyToPresent.get(s.surface.get()) >= + s.bufferData->barrierFrameNumber); + if (!willApplyBarrierFrame) { + ATRACE_NAME("NotReadyBarrier"); + ready = TransactionReadiness::NotReadyBarrier; + return false; } - transaction.traverseStatesWithBuffers([&](const layer_state_t& state) { - const bool frameNumberChanged = state.bufferData->flags.test( - BufferData::BufferDataChange::frameNumberChanged); - if (frameNumberChanged) { - bufferLayersReadyToPresent[state.surface] = state.bufferData->frameNumber; - } else { - // Barrier function only used for BBQ which always includes a frame number - bufferLayersReadyToPresent[state.surface] = - std::numeric_limits::max(); + } + + // If backpressure is enabled and we already have a buffer to commit, keep + // the transaction in the queue. + const bool hasPendingBuffer = + flushState.bufferLayersReadyToPresent.contains(s.surface.get()); + if (layer->backpressureEnabled() && hasPendingBuffer && transaction.isAutoTimestamp) { + ATRACE_NAME("hasPendingBuffer"); + ready = TransactionReadiness::NotReady; + return false; + } + + // check fence status + const bool allowLatchUnsignaled = shouldLatchUnsignaled(layer, s, transaction.states.size(), + flushState.firstTransaction); + ATRACE_FORMAT("%s allowLatchUnsignaled=%s", layer->getName().c_str(), + allowLatchUnsignaled ? "true" : "false"); + + const bool acquireFenceChanged = s.bufferData && + s.bufferData->flags.test(BufferData::BufferDataChange::fenceChanged) && + s.bufferData->acquireFence; + const bool fenceSignaled = + (!acquireFenceChanged || + s.bufferData->acquireFence->getStatus() != Fence::Status::Unsignaled); + if (!fenceSignaled) { + if (!allowLatchUnsignaled) { + ready = TransactionReadiness::NotReady; + auto& listener = s.bufferData->releaseBufferListener; + if (listener && + (flushState.queueProcessTime - transaction.postTime) > + std::chrono::nanoseconds(4s).count()) { + mTransactionHandler.onTransactionQueueStalled(transaction, listener); } - }); - const bool appliedUnsignaled = (ready == TransactionReadiness::ReadyUnsignaled); - if (appliedUnsignaled) { - applyTokensWithUnsignaledTransactions.insert(transaction.applyToken); + return false; } - transactions.emplace_back(std::move(transaction)); - transactionQueue.pop(); - mPendingTransactionCount--; - ATRACE_INT("TransactionQueue", mPendingTransactionCount.load()); + ready = enableLatchUnsignaledConfig == LatchUnsignaledConfig::AutoSingleLayer + ? TransactionReadiness::ReadyUnsignaledSingle + : TransactionReadiness::ReadyUnsignaled; } + return true; + }); + ATRACE_INT("TransactionReadiness", static_cast(ready)); + return ready; +} - if (transactionQueue.empty()) { - it = mPendingTransactionQueues.erase(it); - } else { - it = std::next(it, 1); - } - } - return transactionsPendingBarrier; +void SurfaceFlinger::addTransactionReadyFilters() { + mTransactionHandler.addTransactionReadyFilter( + std::bind(&SurfaceFlinger::transactionReadyTimelineCheck, this, std::placeholders::_1)); + mTransactionHandler.addTransactionReadyFilter( + std::bind(&SurfaceFlinger::transactionReadyBufferCheck, this, std::placeholders::_1)); } bool SurfaceFlinger::flushTransactionQueues(VsyncId vsyncId) { // to prevent onHandleDestroyed from being called while the lock is held, // we must keep a copy of the transactions (specifically the composer // states) around outside the scope of the lock - std::vector transactions; - // Layer handles that have transactions with buffers that are ready to be applied. - std::unordered_map, uint64_t, SpHash> bufferLayersReadyToPresent; + std::vector transactions = mTransactionHandler.flushTransactions(); { Mutex::Autolock _l(mStateLock); - { - while (!mLocklessTransactionQueue.isEmpty()) { - auto maybeTransaction = mLocklessTransactionQueue.pop(); - if (!maybeTransaction.has_value()) { - break; - } - auto transaction = maybeTransaction.value(); - mPendingTransactionQueues[transaction.applyToken].push(std::move(transaction)); - } - - // Transactions with a buffer pending on a barrier may be on a different applyToken - // than the transaction which satisfies our barrier. In fact this is the exact use case - // that the primitive is designed for. This means we may first process - // the barrier dependent transaction, determine it ineligible to complete - // and then satisfy in a later inner iteration of flushPendingTransactionQueues. - // The barrier dependent transaction was eligible to be presented in this frame - // but we would have prevented it without case. To fix this we continually - // loop through flushPendingTransactionQueues until we perform an iteration - // where the number of transactionsPendingBarrier doesn't change. This way - // we can continue to resolve dependency chains of barriers as far as possible. - int lastTransactionsPendingBarrier = 0; - int transactionsPendingBarrier = 0; - do { - lastTransactionsPendingBarrier = transactionsPendingBarrier; - transactionsPendingBarrier = - flushPendingTransactionQueues(transactions, bufferLayersReadyToPresent, - /*tryApplyUnsignaled*/ false); - } while (lastTransactionsPendingBarrier != transactionsPendingBarrier); - - // We collected all transactions that could apply without latching unsignaled buffers. - // If we are allowing latch unsignaled of some form, now it's the time to go over the - // transactions that were not applied and try to apply them unsignaled. - if (enableLatchUnsignaledConfig != LatchUnsignaledConfig::Disabled) { - flushPendingTransactionQueues(transactions, bufferLayersReadyToPresent, - /*tryApplyUnsignaled*/ true); - } - - return applyTransactions(transactions, vsyncId); - } + return applyTransactions(transactions, vsyncId); } } @@ -3833,7 +3826,7 @@ bool SurfaceFlinger::applyTransactions(std::vector& transactio } bool SurfaceFlinger::transactionFlushNeeded() { - return !mPendingTransactionQueues.empty() || !mLocklessTransactionQueue.isEmpty(); + return mTransactionHandler.hasPendingTransactions(); } bool SurfaceFlinger::frameIsEarly(TimePoint expectedPresentTime, VsyncId vsyncId) const { @@ -3859,7 +3852,7 @@ bool SurfaceFlinger::frameIsEarly(TimePoint expectedPresentTime, VsyncId vsyncId } bool SurfaceFlinger::shouldLatchUnsignaled(const sp& layer, const layer_state_t& state, - size_t numStates, size_t totalTXapplied) const { + size_t numStates, bool firstTransaction) const { if (enableLatchUnsignaledConfig == LatchUnsignaledConfig::Disabled) { ALOGV("%s: false (LatchUnsignaledConfig::Disabled)", __func__); return false; @@ -3878,9 +3871,9 @@ bool SurfaceFlinger::shouldLatchUnsignaled(const sp& layer, const layer_s } if (enableLatchUnsignaledConfig == LatchUnsignaledConfig::AutoSingleLayer) { - if (totalTXapplied > 0) { - ALOGV("%s: false (LatchUnsignaledConfig::AutoSingleLayer; totalTXapplied=%zu)", - __func__, totalTXapplied); + if (!firstTransaction) { + ALOGV("%s: false (LatchUnsignaledConfig::AutoSingleLayer; not first transaction)", + __func__); return false; } @@ -3904,116 +3897,6 @@ bool SurfaceFlinger::shouldLatchUnsignaled(const sp& layer, const layer_s return true; } -auto SurfaceFlinger::transactionIsReadyToBeApplied( - TransactionState& transaction, const FrameTimelineInfo& info, bool isAutoTimestamp, - TimePoint desiredPresentTime, uid_t originUid, const Vector& states, - const std::unordered_map, uint64_t, SpHash>& - bufferLayersReadyToPresent, - size_t totalTXapplied, bool tryApplyUnsignaled) const -> TransactionReadiness { - ATRACE_FORMAT("transactionIsReadyToBeApplied vsyncId: %" PRId64, info.vsyncId); - // Do not present if the desiredPresentTime has not passed unless it is more than one second - // in the future. We ignore timestamps more than 1 second in the future for stability reasons. - if (!isAutoTimestamp && desiredPresentTime >= mExpectedPresentTime && - desiredPresentTime < mExpectedPresentTime + 1s) { - ATRACE_NAME("not current"); - return TransactionReadiness::NotReady; - } - - if (!mScheduler->isVsyncValid(mExpectedPresentTime, originUid)) { - ATRACE_NAME("!isVsyncValid"); - return TransactionReadiness::NotReady; - } - - // If the client didn't specify desiredPresentTime, use the vsyncId to determine the expected - // present time of this transaction. - if (isAutoTimestamp && frameIsEarly(mExpectedPresentTime, VsyncId{info.vsyncId})) { - ATRACE_NAME("frameIsEarly"); - return TransactionReadiness::NotReady; - } - - bool fenceUnsignaled = false; - auto queueProcessTime = systemTime(); - for (const ComposerState& state : states) { - const layer_state_t& s = state.state; - - sp layer = nullptr; - if (s.surface) { - layer = fromHandle(s.surface).promote(); - } else if (s.hasBufferChanges()) { - ALOGW("Transaction with buffer, but no Layer?"); - continue; - } - if (!layer) { - continue; - } - - if (s.hasBufferChanges() && s.bufferData->hasBarrier && - ((layer->getDrawingState().frameNumber) < s.bufferData->barrierFrameNumber)) { - const bool willApplyBarrierFrame = - (bufferLayersReadyToPresent.find(s.surface) != bufferLayersReadyToPresent.end()) && - (bufferLayersReadyToPresent.at(s.surface) >= s.bufferData->barrierFrameNumber); - if (!willApplyBarrierFrame) { - ATRACE_NAME("NotReadyBarrier"); - return TransactionReadiness::NotReadyBarrier; - } - } - - const bool allowLatchUnsignaled = tryApplyUnsignaled && - shouldLatchUnsignaled(layer, s, states.size(), totalTXapplied); - ATRACE_FORMAT("%s allowLatchUnsignaled=%s", layer->getName().c_str(), - allowLatchUnsignaled ? "true" : "false"); - - const bool acquireFenceChanged = s.bufferData && - s.bufferData->flags.test(BufferData::BufferDataChange::fenceChanged) && - s.bufferData->acquireFence; - fenceUnsignaled = fenceUnsignaled || - (acquireFenceChanged && - s.bufferData->acquireFence->getStatus() == Fence::Status::Unsignaled); - - if (fenceUnsignaled && !allowLatchUnsignaled) { - if (!transaction.sentFenceTimeoutWarning && - queueProcessTime - transaction.postTime > std::chrono::nanoseconds(4s).count()) { - transaction.sentFenceTimeoutWarning = true; - auto listener = s.bufferData->releaseBufferListener; - if (listener) { - listener->onTransactionQueueStalled(); - } - } - - ATRACE_NAME("fence unsignaled"); - return TransactionReadiness::NotReady; - } - - if (s.hasBufferChanges()) { - // If backpressure is enabled and we already have a buffer to commit, keep the - // transaction in the queue. - const bool hasPendingBuffer = bufferLayersReadyToPresent.find(s.surface) != - bufferLayersReadyToPresent.end(); - if (layer->backpressureEnabled() && hasPendingBuffer && isAutoTimestamp) { - ATRACE_NAME("hasPendingBuffer"); - return TransactionReadiness::NotReady; - } - } - } - return fenceUnsignaled ? TransactionReadiness::ReadyUnsignaled : TransactionReadiness::Ready; -} - -void SurfaceFlinger::queueTransaction(TransactionState& state) { - mLocklessTransactionQueue.push(state); - mPendingTransactionCount++; - ATRACE_INT("TransactionQueue", mPendingTransactionCount.load()); - - const auto schedule = [](uint32_t flags) { - if (flags & eEarlyWakeupEnd) return TransactionSchedule::EarlyEnd; - if (flags & eEarlyWakeupStart) return TransactionSchedule::EarlyStart; - return TransactionSchedule::Late; - }(state.flags); - - const auto frameHint = state.isFrameActive() ? FrameHint::kActive : FrameHint::kNone; - - setTransactionFlags(eTransactionFlushNeeded, schedule, state.applyToken, frameHint); -} - status_t SurfaceFlinger::setTransactionState( const FrameTimelineInfo& frameTimelineInfo, const Vector& states, const Vector& displays, uint32_t flags, const sp& applyToken, @@ -4064,7 +3947,16 @@ status_t SurfaceFlinger::setTransactionState( if (mTransactionTracing) { mTransactionTracing->addQueuedTransaction(state); } - queueTransaction(state); + + const auto schedule = [](uint32_t flags) { + if (flags & eEarlyWakeupEnd) return TransactionSchedule::EarlyEnd; + if (flags & eEarlyWakeupStart) return TransactionSchedule::EarlyStart; + return TransactionSchedule::Late; + }(state.flags); + + const auto frameHint = state.isFrameActive() ? FrameHint::kActive : FrameHint::kNone; + setTransactionFlags(eTransactionFlushNeeded, schedule, state.applyToken, frameHint); + mTransactionHandler.queueTransaction(std::move(state)); return NO_ERROR; } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index baaf41ec02..f4fb8de010 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -57,7 +57,6 @@ #include #include -#include "ClientCache.h" #include "Display/DisplayMap.h" #include "Display/PhysicalDisplay.h" #include "DisplayDevice.h" @@ -66,19 +65,17 @@ #include "DisplayIdGenerator.h" #include "Effects/Daltonizer.h" #include "FlagManager.h" -#include "FrameTracker.h" #include "LayerVector.h" -#include "LocklessQueue.h" #include "Scheduler/RefreshRateConfigs.h" #include "Scheduler/RefreshRateStats.h" #include "Scheduler/Scheduler.h" #include "Scheduler/VsyncModulator.h" #include "SurfaceFlingerFactory.h" #include "ThreadContext.h" -#include "TracedOrdinal.h" #include "Tracing/LayerTracing.h" #include "Tracing/TransactionTracing.h" #include "TransactionCallbackInvoker.h" +#include "TransactionHandler.h" #include "TransactionState.h" #include @@ -341,6 +338,7 @@ private: friend class RegionSamplingThread; friend class LayerRenderArea; friend class LayerTracing; + friend class SurfaceComposerAIDL; // For unit tests friend class TestableSurfaceFlinger; @@ -729,11 +727,13 @@ private: bool flushTransactionQueues(VsyncId) REQUIRES(kMainThreadContext); // Returns true if there is at least one transaction that needs to be flushed bool transactionFlushNeeded(); - - int flushPendingTransactionQueues( - std::vector& transactions, - std::unordered_map, uint64_t, SpHash>& bufferLayersReadyToPresent, - bool tryApplyUnsignaled) REQUIRES(mStateLock) REQUIRES(kMainThreadContext); + void addTransactionReadyFilters(); + TransactionHandler::TransactionReadiness transactionReadyTimelineCheck( + const TransactionHandler::TransactionFlushState& flushState) + REQUIRES(kMainThreadContext); + TransactionHandler::TransactionReadiness transactionReadyBufferCheck( + const TransactionHandler::TransactionFlushState& flushState) + REQUIRES(kMainThreadContext); uint32_t setClientStateLocked(const FrameTimelineInfo&, ComposerState&, int64_t desiredPresentTime, bool isAutoTimestamp, @@ -751,23 +751,9 @@ private: void commitOffscreenLayers(); - enum class TransactionReadiness { - NotReady, - NotReadyBarrier, - Ready, - ReadyUnsignaled, - }; - TransactionReadiness transactionIsReadyToBeApplied( - TransactionState&, const FrameTimelineInfo&, bool isAutoTimestamp, - TimePoint desiredPresentTime, uid_t originUid, const Vector&, - const std::unordered_map, uint64_t, SpHash>& - bufferLayersReadyToPresent, - size_t totalTXapplied, bool tryApplyUnsignaled) const REQUIRES(mStateLock) - REQUIRES(kMainThreadContext); - static LatchUnsignaledConfig getLatchUnsignaledConfig(); bool shouldLatchUnsignaled(const sp& layer, const layer_state_t&, size_t numStates, - size_t totalTXapplied) const; + bool firstTransaction) const; bool applyTransactions(std::vector& transactions, VsyncId) REQUIRES(mStateLock); uint32_t setDisplayStateLocked(const DisplayState& s) REQUIRES(mStateLock); @@ -1094,7 +1080,6 @@ private: status_t CheckTransactCodeCredentials(uint32_t code); // Add transaction to the Transaction Queue - void queueTransaction(TransactionState& state); /* * Generic Layer Metadata @@ -1256,10 +1241,6 @@ private: uint32_t mTexturePoolSize = 0; std::vector mTexturePool; - std::unordered_map, std::queue, IListenerHash> - mPendingTransactionQueues; - LocklessQueue mLocklessTransactionQueue; - std::atomic mPendingTransactionCount = 0; std::atomic mNumLayers = 0; // to linkToDeath @@ -1415,7 +1396,7 @@ private: bool early = false; } mPowerHintSessionMode; - friend class SurfaceComposerAIDL; + TransactionHandler mTransactionHandler; }; class SurfaceComposerAIDL : public gui::BnSurfaceComposer { diff --git a/services/surfaceflinger/Tracing/TransactionProtoParser.h b/services/surfaceflinger/Tracing/TransactionProtoParser.h index 872a901b21..2232bb9cb1 100644 --- a/services/surfaceflinger/Tracing/TransactionProtoParser.h +++ b/services/surfaceflinger/Tracing/TransactionProtoParser.h @@ -15,6 +15,7 @@ */ #pragma once +#include #include #include @@ -43,35 +44,6 @@ struct TracingLayerState : layer_state_t { TracingLayerCreationArgs args; }; -// Class which exposes buffer properties from BufferData without holding on to the actual buffer -// handle. -class BufferDataStub : public BufferData { -public: - BufferDataStub(uint64_t bufferId, uint32_t width, uint32_t height, int32_t pixelFormat, - uint64_t outUsage) - : mBufferId(bufferId), - mWidth(width), - mHeight(height), - mPixelFormat(pixelFormat), - mOutUsage(outUsage) {} - bool hasBuffer() const override { return mBufferId != 0; } - bool hasSameBuffer(const BufferData& other) const override { - return getId() == other.getId() && frameNumber == other.frameNumber; - } - uint32_t getWidth() const override { return mWidth; } - uint32_t getHeight() const override { return mHeight; } - uint64_t getId() const override { return mBufferId; } - PixelFormat getPixelFormat() const override { return mPixelFormat; } - uint64_t getUsage() const override { return mOutUsage; } - -private: - uint64_t mBufferId; - uint32_t mWidth; - uint32_t mHeight; - int32_t mPixelFormat; - uint64_t mOutUsage; -}; - class TransactionProtoParser { public: // Utility class to map handles to ids and buffers to buffer properties without pulling @@ -87,7 +59,7 @@ public: virtual std::shared_ptr getGraphicData(uint64_t bufferId, uint32_t width, uint32_t height, int32_t pixelFormat, uint64_t usage) const { - return std::make_shared(bufferId, width, height, pixelFormat, usage); + return std::make_shared(bufferId, width, height, pixelFormat, usage); } virtual void getGraphicBufferPropertiesFromCache(client_cache_t /* cachedBuffer */, uint64_t* /* outBufferId */, diff --git a/services/surfaceflinger/TransactionHandler.cpp b/services/surfaceflinger/TransactionHandler.cpp new file mode 100644 index 0000000000..6c6a487b67 --- /dev/null +++ b/services/surfaceflinger/TransactionHandler.cpp @@ -0,0 +1,188 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// #define LOG_NDEBUG 0 +#undef LOG_TAG +#define LOG_TAG "TransactionHandler" +#define ATRACE_TAG ATRACE_TAG_GRAPHICS + +#include +#include + +#include "TransactionHandler.h" + +namespace android { + +void TransactionHandler::queueTransaction(TransactionState&& state) { + mLocklessTransactionQueue.push(std::move(state)); + mPendingTransactionCount.fetch_add(1); + ATRACE_INT("TransactionQueue", static_cast(mPendingTransactionCount.load())); +} + +std::vector TransactionHandler::flushTransactions() { + while (!mLocklessTransactionQueue.isEmpty()) { + auto maybeTransaction = mLocklessTransactionQueue.pop(); + if (!maybeTransaction.has_value()) { + break; + } + auto transaction = maybeTransaction.value(); + mPendingTransactionQueues[transaction.applyToken].emplace(std::move(transaction)); + } + + // Collect transaction that are ready to be applied. + std::vector transactions; + TransactionFlushState flushState; + flushState.queueProcessTime = systemTime(); + // Transactions with a buffer pending on a barrier may be on a different applyToken + // than the transaction which satisfies our barrier. In fact this is the exact use case + // that the primitive is designed for. This means we may first process + // the barrier dependent transaction, determine it ineligible to complete + // and then satisfy in a later inner iteration of flushPendingTransactionQueues. + // The barrier dependent transaction was eligible to be presented in this frame + // but we would have prevented it without case. To fix this we continually + // loop through flushPendingTransactionQueues until we perform an iteration + // where the number of transactionsPendingBarrier doesn't change. This way + // we can continue to resolve dependency chains of barriers as far as possible. + int lastTransactionsPendingBarrier = 0; + int transactionsPendingBarrier = 0; + do { + lastTransactionsPendingBarrier = transactionsPendingBarrier; + // Collect transactions that are ready to be applied. + transactionsPendingBarrier = flushPendingTransactionQueues(transactions, flushState); + } while (lastTransactionsPendingBarrier != transactionsPendingBarrier); + + mPendingTransactionCount.fetch_sub(transactions.size()); + ATRACE_INT("TransactionQueue", static_cast(mPendingTransactionCount.load())); + return transactions; +} + +TransactionHandler::TransactionReadiness TransactionHandler::applyFilters( + TransactionFlushState& flushState) { + auto ready = TransactionReadiness::Ready; + for (auto& filter : mTransactionReadyFilters) { + auto perFilterReady = filter(flushState); + switch (perFilterReady) { + case TransactionReadiness::NotReady: + case TransactionReadiness::NotReadyBarrier: + return perFilterReady; + + case TransactionReadiness::ReadyUnsignaled: + case TransactionReadiness::ReadyUnsignaledSingle: + // If one of the filters allows latching an unsignaled buffer, latch this ready + // state. + ready = perFilterReady; + break; + case TransactionReadiness::Ready: + continue; + } + } + return ready; +} + +int TransactionHandler::flushPendingTransactionQueues(std::vector& transactions, + TransactionFlushState& flushState) { + int transactionsPendingBarrier = 0; + auto it = mPendingTransactionQueues.begin(); + while (it != mPendingTransactionQueues.end()) { + auto& queue = it->second; + IBinder* queueToken = it->first.get(); + + // if we have already flushed a transaction with an unsignaled buffer then stop queue + // processing + if (std::find(flushState.queuesWithUnsignaledBuffers.begin(), + flushState.queuesWithUnsignaledBuffers.end(), + queueToken) != flushState.queuesWithUnsignaledBuffers.end()) { + continue; + } + + while (!queue.empty()) { + auto& transaction = queue.front(); + flushState.transaction = &transaction; + auto ready = applyFilters(flushState); + if (ready == TransactionReadiness::NotReadyBarrier) { + transactionsPendingBarrier++; + break; + } else if (ready == TransactionReadiness::NotReady) { + break; + } + + // Transaction is ready move it from the pending queue. + flushState.firstTransaction = false; + removeFromStalledTransactions(transaction.id); + transactions.emplace_back(std::move(transaction)); + queue.pop(); + + // If the buffer is unsignaled, then we don't want to signal other transactions using + // the buffer as a barrier. + auto& readyToApplyTransaction = transactions.back(); + if (ready == TransactionReadiness::Ready) { + readyToApplyTransaction.traverseStatesWithBuffers([&](const layer_state_t& state) { + const bool frameNumberChanged = state.bufferData->flags.test( + BufferData::BufferDataChange::frameNumberChanged); + if (frameNumberChanged) { + flushState.bufferLayersReadyToPresent + .emplace_or_replace(state.surface.get(), + state.bufferData->frameNumber); + } else { + // Barrier function only used for BBQ which always includes a frame number. + // This value only used for barrier logic. + flushState.bufferLayersReadyToPresent + .emplace_or_replace(state.surface.get(), + std::numeric_limits::max()); + } + }); + } else if (ready == TransactionReadiness::ReadyUnsignaledSingle) { + // Track queues with a flushed unsingaled buffer. + flushState.queuesWithUnsignaledBuffers.emplace_back(queueToken); + break; + } + } + + if (queue.empty()) { + it = mPendingTransactionQueues.erase(it); + } else { + it = std::next(it, 1); + } + } + return transactionsPendingBarrier; +} + +void TransactionHandler::addTransactionReadyFilter(TransactionFilter&& filter) { + mTransactionReadyFilters.emplace_back(std::move(filter)); +} + +bool TransactionHandler::hasPendingTransactions() { + return !mPendingTransactionQueues.empty() || !mLocklessTransactionQueue.isEmpty(); +} + +void TransactionHandler::onTransactionQueueStalled(const TransactionState& transaction, + sp& listener) { + if (std::find(mStalledTransactions.begin(), mStalledTransactions.end(), transaction.id) != + mStalledTransactions.end()) { + return; + } + + mStalledTransactions.push_back(transaction.id); + listener->onTransactionQueueStalled(); +} + +void TransactionHandler::removeFromStalledTransactions(uint64_t id) { + auto it = std::find(mStalledTransactions.begin(), mStalledTransactions.end(), id); + if (it != mStalledTransactions.end()) { + mStalledTransactions.erase(it); + } +} +} // namespace android \ No newline at end of file diff --git a/services/surfaceflinger/TransactionHandler.h b/services/surfaceflinger/TransactionHandler.h new file mode 100644 index 0000000000..237b48d55f --- /dev/null +++ b/services/surfaceflinger/TransactionHandler.h @@ -0,0 +1,74 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace android { +class TransactionHandler { +public: + struct TransactionFlushState { + const TransactionState* transaction; + bool firstTransaction = true; + nsecs_t queueProcessTime = 0; + // Layer handles that have transactions with buffers that are ready to be applied. + ftl::SmallMap + bufferLayersReadyToPresent = {}; + ftl::SmallVector queuesWithUnsignaledBuffers; + }; + enum class TransactionReadiness { + NotReady, + NotReadyBarrier, + Ready, + ReadyUnsignaled, + ReadyUnsignaledSingle, + }; + using TransactionFilter = std::function; + + bool hasPendingTransactions(); + std::vector flushTransactions(); + void addTransactionReadyFilter(TransactionFilter&&); + void queueTransaction(TransactionState&&); + void onTransactionQueueStalled(const TransactionState&, sp&); + void removeFromStalledTransactions(uint64_t transactionId); + +private: + // For unit tests + friend class TestableSurfaceFlinger; + + int flushPendingTransactionQueues(std::vector&, TransactionFlushState&); + TransactionReadiness applyFilters(TransactionFlushState&); + std::unordered_map, std::queue, IListenerHash> + mPendingTransactionQueues; + LocklessQueue mLocklessTransactionQueue; + std::atomic mPendingTransactionCount = 0; + ftl::SmallVector mTransactionReadyFilters; + std::vector mStalledTransactions; +}; + +} // namespace android diff --git a/services/surfaceflinger/TransactionState.h b/services/surfaceflinger/TransactionState.h index 95eb503327..3cbfe811ea 100644 --- a/services/surfaceflinger/TransactionState.h +++ b/services/surfaceflinger/TransactionState.h @@ -64,6 +64,15 @@ struct TransactionState { } } + template + void traverseStatesWithBuffersWhileTrue(Visitor&& visitor) const { + for (const auto& [state] : states) { + if (state.hasBufferChanges() && state.hasValidBuffer() && state.surface) { + if (!visitor(state)) return; + } + } + } + // TODO(b/185535769): Remove FrameHint. Instead, reset the idle timer (of the relevant physical // display) on the main thread if commit leads to composite. Then, RefreshRateOverlay should be // able to setFrameRate once, rather than for each transaction. diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h index 370b23c7ce..49dd80ede7 100644 --- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h +++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h @@ -728,8 +728,10 @@ public: return mFlinger->setPowerModeInternal(display, mode); } - auto &getTransactionQueue() { return mFlinger->mLocklessTransactionQueue; } - auto &getPendingTransactionQueue() { return mFlinger->mPendingTransactionQueues; } + auto &getTransactionQueue() { return mFlinger->mTransactionHandler.mLocklessTransactionQueue; } + auto &getPendingTransactionQueue() { + return mFlinger->mTransactionHandler.mPendingTransactionQueues; + } auto setTransactionState( const FrameTimelineInfo &frameTimelineInfo, const Vector &states, diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index e1a0eeb7fe..7b319f52c5 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -417,8 +417,13 @@ public: return mFlinger->SurfaceFlinger::getDisplayNativePrimaries(displayToken, primaries); } - auto& getTransactionQueue() { return mFlinger->mLocklessTransactionQueue; } - auto& getPendingTransactionQueue() { return mFlinger->mPendingTransactionQueues; } + auto& getTransactionQueue() { return mFlinger->mTransactionHandler.mLocklessTransactionQueue; } + auto& getPendingTransactionQueue() { + return mFlinger->mTransactionHandler.mPendingTransactionQueues; + } + size_t getPendingTransactionCount() { + return mFlinger->mTransactionHandler.mPendingTransactionCount.load(); + } auto setTransactionState( const FrameTimelineInfo& frameTimelineInfo, const Vector& states, diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp index b4030b3617..db438b70ab 100644 --- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp @@ -14,7 +14,6 @@ * limitations under the License. */ - #undef LOG_TAG #define LOG_TAG "CompositionTest" @@ -22,12 +21,17 @@ #include #include #include +#include #include +#include #include #include #include +#include +#include #include "TestableSurfaceFlinger.h" +#include "TransactionHandler.h" #include "mock/MockEventThread.h" #include "mock/MockVsyncController.h" @@ -78,6 +82,7 @@ public: mFlinger.setupScheduler(std::unique_ptr(mVsyncController), std::unique_ptr(mVSyncTracker), std::move(eventThread), std::move(sfEventThread)); + mFlinger.flinger()->addTransactionReadyFilters(); } TestableSurfaceFlinger mFlinger; @@ -314,7 +319,10 @@ public: ComposerState createComposerState(int layerId, sp fence, uint64_t what) { ComposerState state; - state.state.bufferData = std::make_shared(); + state.state.bufferData = + std::make_shared(/* bufferId */ 123L, /* width */ 1, + /* height */ 2, /* pixelFormat */ 0, + /* outUsage */ 0); state.state.bufferData->acquireFence = std::move(fence); state.state.layerId = layerId; state.state.surface = @@ -361,7 +369,7 @@ public: } mFlinger.flushTransactionQueues(); EXPECT_TRUE(mFlinger.getTransactionQueue().isEmpty()); - EXPECT_EQ(expectedTransactionsPending, mFlinger.getPendingTransactionQueue().size()); + EXPECT_EQ(expectedTransactionsPending, mFlinger.getPendingTransactionCount()); } }; @@ -413,7 +421,9 @@ TEST_F(LatchUnsignaledAutoSingleLayerTest, Flush_KeepsUnSignaledInTheQueue_NonBu { createComposerState(kLayerId, fence(Fence::Status::Unsignaled), - layer_state_t::eCropChanged), + layer_state_t::eCropChanged | + layer_state_t:: + eBufferChanged), }); setTransactionStates({unsignaledTransaction}, kExpectedTransactionsPending); } @@ -536,41 +546,6 @@ TEST_F(LatchUnsignaledAutoSingleLayerTest, kExpectedTransactionsPending); } -TEST_F(LatchUnsignaledAutoSingleLayerTest, UnsignaledNotAppliedWhenThereAreSignaled_SignaledFirst) { - const sp kApplyToken1 = - IInterface::asBinder(TransactionCompletedListener::getIInstance()); - const sp kApplyToken2 = sp::make(); - const sp kApplyToken3 = sp::make(); - const auto kLayerId1 = 1; - const auto kLayerId2 = 2; - const auto kExpectedTransactionsPending = 1u; - - const auto signaledTransaction = - createTransactionInfo(kApplyToken1, - { - createComposerState(kLayerId1, - fence(Fence::Status::Signaled), - layer_state_t::eBufferChanged), - }); - const auto signaledTransaction2 = - createTransactionInfo(kApplyToken2, - { - createComposerState(kLayerId1, - fence(Fence::Status::Signaled), - layer_state_t::eBufferChanged), - }); - const auto unsignaledTransaction = - createTransactionInfo(kApplyToken3, - { - createComposerState(kLayerId2, - fence(Fence::Status::Unsignaled), - layer_state_t::eBufferChanged), - }); - - setTransactionStates({signaledTransaction, signaledTransaction2, unsignaledTransaction}, - kExpectedTransactionsPending); -} - TEST_F(LatchUnsignaledAutoSingleLayerTest, Flush_KeepsTransactionInTheQueueSameApplyToken) { const sp kApplyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance()); @@ -798,7 +773,7 @@ TEST_F(LatchUnsignaledDisabledTest, Flush_KeepInTheUnsignaledTheQueue) { IInterface::asBinder(TransactionCompletedListener::getIInstance()); const auto kLayerId1 = 1; const auto kLayerId2 = 2; - const auto kExpectedTransactionsPending = 1u; + const auto kExpectedTransactionsPending = 2u; const auto unsignaledTransaction = createTransactionInfo(kApplyToken, @@ -1004,4 +979,16 @@ TEST_F(LatchUnsignaledAlwaysTest, LatchUnsignaledWhenEarlyOffset) { setTransactionStates({unsignaledTransaction}, kExpectedTransactionsPending); } +TEST(TransactionHandlerTest, QueueTransaction) { + TransactionHandler handler; + TransactionState transaction; + transaction.applyToken = sp::make(); + transaction.id = 42; + handler.queueTransaction(std::move(transaction)); + std::vector transactionsReadyToBeApplied = handler.flushTransactions(); + + EXPECT_EQ(transactionsReadyToBeApplied.size(), 1u); + EXPECT_EQ(transactionsReadyToBeApplied.front().id, 42u); +} + } // namespace android -- cgit v1.2.3-59-g8ed1b From bbceb46b722db9d1ececb909c845e45302721f89 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Mon, 10 Oct 2022 04:52:13 +0000 Subject: SurfaceComposerClient: Clean up layer state - align layer alpha/color with SF layer drawing state - remove unused flags and fields Bug: 238781169 Test: presubmit Change-Id: I4be9c56b3006b7d7a0ca19160511ebb9e3551a8c --- libs/gui/LayerState.cpp | 31 ++++++++++------------ libs/gui/SurfaceComposerClient.cpp | 10 +++---- libs/gui/include/gui/LayerState.h | 15 +++++------ services/surfaceflinger/Layer.cpp | 15 +++++------ services/surfaceflinger/SurfaceFlinger.cpp | 12 ++++----- .../Tracing/TransactionProtoParser.cpp | 12 ++++----- .../surfaceflinger/layerproto/transactions.proto | 3 +-- 7 files changed, 44 insertions(+), 54 deletions(-) (limited to 'libs/gui/LayerState.cpp') diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 2759c58fb1..924e65ec4a 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -40,13 +40,13 @@ layer_state_t::layer_state_t() x(0), y(0), z(0), - alpha(0), flags(0), mask(0), reserved(0), cornerRadius(0.0f), backgroundBlurRadius(0), - transform(0), + color(0), + bufferTransform(0), transformToDisplayInverse(false), crop(Rect::INVALID_RECT), dataspace(ui::Dataspace::UNKNOWN), @@ -83,20 +83,19 @@ status_t layer_state_t::write(Parcel& output) const SAFE_PARCEL(output.writeFloat, y); SAFE_PARCEL(output.writeInt32, z); SAFE_PARCEL(output.writeUint32, layerStack.id); - SAFE_PARCEL(output.writeFloat, alpha); SAFE_PARCEL(output.writeUint32, flags); SAFE_PARCEL(output.writeUint32, mask); SAFE_PARCEL(matrix.write, output); SAFE_PARCEL(output.write, crop); - SAFE_PARCEL(SurfaceControl::writeNullableToParcel, output, reparentSurfaceControl); SAFE_PARCEL(SurfaceControl::writeNullableToParcel, output, relativeLayerSurfaceControl); SAFE_PARCEL(SurfaceControl::writeNullableToParcel, output, parentSurfaceControlForChild); SAFE_PARCEL(output.writeFloat, color.r); SAFE_PARCEL(output.writeFloat, color.g); SAFE_PARCEL(output.writeFloat, color.b); + SAFE_PARCEL(output.writeFloat, color.a); SAFE_PARCEL(windowInfoHandle->writeToParcel, &output); SAFE_PARCEL(output.write, transparentRegion); - SAFE_PARCEL(output.writeUint32, transform); + SAFE_PARCEL(output.writeUint32, bufferTransform); SAFE_PARCEL(output.writeBool, transformToDisplayInverse); SAFE_PARCEL(output.writeBool, borderEnabled); SAFE_PARCEL(output.writeFloat, borderWidth); @@ -177,7 +176,6 @@ status_t layer_state_t::read(const Parcel& input) SAFE_PARCEL(input.readFloat, &y); SAFE_PARCEL(input.readInt32, &z); SAFE_PARCEL(input.readUint32, &layerStack.id); - SAFE_PARCEL(input.readFloat, &alpha); SAFE_PARCEL(input.readUint32, &flags); @@ -185,7 +183,6 @@ status_t layer_state_t::read(const Parcel& input) SAFE_PARCEL(matrix.read, input); SAFE_PARCEL(input.read, crop); - SAFE_PARCEL(SurfaceControl::readNullableFromParcel, input, &reparentSurfaceControl); SAFE_PARCEL(SurfaceControl::readNullableFromParcel, input, &relativeLayerSurfaceControl); SAFE_PARCEL(SurfaceControl::readNullableFromParcel, input, &parentSurfaceControlForChild); @@ -197,10 +194,13 @@ status_t layer_state_t::read(const Parcel& input) color.g = tmpFloat; SAFE_PARCEL(input.readFloat, &tmpFloat); color.b = tmpFloat; + SAFE_PARCEL(input.readFloat, &tmpFloat); + color.a = tmpFloat; + SAFE_PARCEL(windowInfoHandle->readFromParcel, &input); SAFE_PARCEL(input.read, transparentRegion); - SAFE_PARCEL(input.readUint32, &transform); + SAFE_PARCEL(input.readUint32, &bufferTransform); SAFE_PARCEL(input.readBool, &transformToDisplayInverse); SAFE_PARCEL(input.readBool, &borderEnabled); SAFE_PARCEL(input.readFloat, &tmpFloat); @@ -453,7 +453,7 @@ void layer_state_t::merge(const layer_state_t& other) { } if (other.what & eAlphaChanged) { what |= eAlphaChanged; - alpha = other.alpha; + color.a = other.color.a; } if (other.what & eMatrixChanged) { what |= eMatrixChanged; @@ -495,12 +495,9 @@ void layer_state_t::merge(const layer_state_t& other) { what |= eReparent; parentSurfaceControlForChild = other.parentSurfaceControlForChild; } - if (other.what & eDestroySurface) { - what |= eDestroySurface; - } - if (other.what & eTransformChanged) { - what |= eTransformChanged; - transform = other.transform; + if (other.what & eBufferTransformChanged) { + what |= eBufferTransformChanged; + bufferTransform = other.bufferTransform; } if (other.what & eTransformToDisplayInverseChanged) { what |= eTransformToDisplayInverseChanged; @@ -547,7 +544,7 @@ void layer_state_t::merge(const layer_state_t& other) { } if (other.what & eBackgroundColorChanged) { what |= eBackgroundColorChanged; - color = other.color; + color.rgb = other.color.rgb; bgColorAlpha = other.bgColorAlpha; bgColorDataspace = other.bgColorDataspace; } @@ -612,7 +609,7 @@ void layer_state_t::merge(const layer_state_t& other) { } if (other.what & eColorChanged) { what |= eColorChanged; - color = other.color; + color.rgb = other.color.rgb; } if (other.what & eColorSpaceAgnosticChanged) { what |= eColorSpaceAgnosticChanged; diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 694bc5af5b..fee45ea693 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1293,7 +1293,7 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setAlpha ALOGE("SurfaceComposerClient::Transaction::setAlpha: invalid alpha %f, clamping", alpha); } s->what |= layer_state_t::eAlphaChanged; - s->alpha = std::clamp(alpha, 0.f, 1.f); + s->color.a = std::clamp(alpha, 0.f, 1.f); registerSurfaceControlForCallback(sc); return *this; @@ -1424,7 +1424,7 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setColor return *this; } s->what |= layer_state_t::eColorChanged; - s->color = color; + s->color.rgb = color; registerSurfaceControlForCallback(sc); return *this; @@ -1439,7 +1439,7 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBackg } s->what |= layer_state_t::eBackgroundColorChanged; - s->color = color; + s->color.rgb = color; s->bgColorAlpha = alpha; s->bgColorDataspace = dataspace; @@ -1454,8 +1454,8 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setTrans mStatus = BAD_INDEX; return *this; } - s->what |= layer_state_t::eTransformChanged; - s->transform = transform; + s->what |= layer_state_t::eBufferTransformChanged; + s->bufferTransform = transform; registerSurfaceControlForCallback(sc); return *this; diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index c8927ad55a..45272e7431 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -148,12 +148,14 @@ struct layer_state_t { enum { ePositionChanged = 0x00000001, eLayerChanged = 0x00000002, - // unused = 0x00000004, + /* unused = 0x00000004, */ eAlphaChanged = 0x00000008, eMatrixChanged = 0x00000010, eTransparentRegionChanged = 0x00000020, eFlagsChanged = 0x00000040, eLayerStackChanged = 0x00000080, + /* unused = 0x00000100, */ + /* unused = 0x00000200, */ eDimmingEnabledChanged = 0x00000400, eShadowRadiusChanged = 0x00000800, eRenderBorderChanged = 0x00001000, @@ -161,8 +163,8 @@ struct layer_state_t { eRelativeLayerChanged = 0x00004000, eReparent = 0x00008000, eColorChanged = 0x00010000, - eDestroySurface = 0x00020000, - eTransformChanged = 0x00040000, + /* unused = 0x00020000, */ + eBufferTransformChanged = 0x00040000, eTransformToDisplayInverseChanged = 0x00080000, eCropChanged = 0x00100000, eBufferChanged = 0x00200000, @@ -218,25 +220,22 @@ struct layer_state_t { float y; int32_t z; ui::LayerStack layerStack = ui::DEFAULT_LAYER_STACK; - float alpha; uint32_t flags; uint32_t mask; uint8_t reserved; matrix22_t matrix; float cornerRadius; uint32_t backgroundBlurRadius; - sp reparentSurfaceControl; sp relativeLayerSurfaceControl; sp parentSurfaceControlForChild; - half3 color; + half4 color; // non POD must be last. see write/read Region transparentRegion; - - uint32_t transform; + uint32_t bufferTransform; bool transformToDisplayInverse; Rect crop; std::shared_ptr bufferData = nullptr; diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 410e43846d..9bb93050dc 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -3633,7 +3633,7 @@ bool Layer::simpleBufferUpdate(const layer_state_t& s) const { } if (s.what & layer_state_t::eAlphaChanged) { - if (mDrawingState.color.a != s.alpha) { + if (mDrawingState.color.a != s.color.a) { ALOGV("%s: false [eAlphaChanged changed]", __func__); return false; } @@ -3677,9 +3677,9 @@ bool Layer::simpleBufferUpdate(const layer_state_t& s) const { } } - if (s.what & layer_state_t::eTransformChanged) { - if (mDrawingState.bufferTransform != s.transform) { - ALOGV("%s: false [eTransformChanged changed]", __func__); + if (s.what & layer_state_t::eBufferTransformChanged) { + if (mDrawingState.bufferTransform != s.bufferTransform) { + ALOGV("%s: false [eBufferTransformChanged changed]", __func__); return false; } } @@ -4177,15 +4177,12 @@ const std::shared_ptr& Layer::getExternalTexture( } bool Layer::setColor(const half3& color) { - if (mDrawingState.color.r == color.r && mDrawingState.color.g == color.g && - mDrawingState.color.b == color.b) { + if (mDrawingState.color.rgb == color) { return false; } mDrawingState.sequence++; - mDrawingState.color.r = color.r; - mDrawingState.color.g = color.g; - mDrawingState.color.b = color.b; + mDrawingState.color.rgb = color; mDrawingState.modified = true; setTransactionFlags(eTransactionNeeded); return true; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 5466497008..3b00ca803e 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -4152,12 +4152,10 @@ uint32_t SurfaceFlinger::setClientStateLocked(const FrameTimelineInfo& frameTime } } if (what & layer_state_t::eAlphaChanged) { - if (layer->setAlpha(s.alpha)) - flags |= eTraversalNeeded; + if (layer->setAlpha(s.color.a)) flags |= eTraversalNeeded; } if (what & layer_state_t::eColorChanged) { - if (layer->setColor(s.color)) - flags |= eTraversalNeeded; + if (layer->setColor(s.color.rgb)) flags |= eTraversalNeeded; } if (what & layer_state_t::eColorTransformChanged) { if (layer->setColorTransform(s.colorTransform)) { @@ -4165,7 +4163,7 @@ uint32_t SurfaceFlinger::setClientStateLocked(const FrameTimelineInfo& frameTime } } if (what & layer_state_t::eBackgroundColorChanged) { - if (layer->setBackgroundColor(s.color, s.bgColorAlpha, s.bgColorDataspace)) { + if (layer->setBackgroundColor(s.color.rgb, s.bgColorAlpha, s.bgColorDataspace)) { flags |= eTraversalNeeded; } } @@ -4214,8 +4212,8 @@ uint32_t SurfaceFlinger::setClientStateLocked(const FrameTimelineInfo& frameTime flags |= eTransactionNeeded | eTraversalNeeded | eTransformHintUpdateNeeded; } } - if (what & layer_state_t::eTransformChanged) { - if (layer->setTransform(s.transform)) flags |= eTraversalNeeded; + if (what & layer_state_t::eBufferTransformChanged) { + if (layer->setTransform(s.bufferTransform)) flags |= eTraversalNeeded; } if (what & layer_state_t::eTransformToDisplayInverseChanged) { if (layer->setTransformToDisplayInverse(s.transformToDisplayInverse)) diff --git a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp index 267f3d0219..3418c82f9e 100644 --- a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp +++ b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp @@ -111,7 +111,7 @@ proto::LayerState TransactionProtoParser::toProto(const layer_state_t& layer) { } if (layer.what & layer_state_t::eAlphaChanged) { - proto.set_alpha(layer.alpha); + proto.set_alpha(layer.color.a); } if (layer.what & layer_state_t::eColorChanged) { @@ -123,8 +123,8 @@ proto::LayerState TransactionProtoParser::toProto(const layer_state_t& layer) { if (layer.what & layer_state_t::eTransparentRegionChanged) { LayerProtoHelper::writeToProto(layer.transparentRegion, proto.mutable_transparent_region()); } - if (layer.what & layer_state_t::eTransformChanged) { - proto.set_transform(layer.transform); + if (layer.what & layer_state_t::eBufferTransformChanged) { + proto.set_transform(layer.bufferTransform); } if (layer.what & layer_state_t::eTransformToDisplayInverseChanged) { proto.set_transform_to_display_inverse(layer.transformToDisplayInverse); @@ -395,7 +395,7 @@ void TransactionProtoParser::fromProto(const proto::LayerState& proto, layer_sta } if (proto.what() & layer_state_t::eAlphaChanged) { - layer.alpha = proto.alpha(); + layer.color.a = proto.alpha(); } if (proto.what() & layer_state_t::eColorChanged) { @@ -407,8 +407,8 @@ void TransactionProtoParser::fromProto(const proto::LayerState& proto, layer_sta if (proto.what() & layer_state_t::eTransparentRegionChanged) { LayerProtoHelper::readFromProto(proto.transparent_region(), layer.transparentRegion); } - if (proto.what() & layer_state_t::eTransformChanged) { - layer.transform = proto.transform(); + if (proto.what() & layer_state_t::eBufferTransformChanged) { + layer.bufferTransform = proto.transform(); } if (proto.what() & layer_state_t::eTransformToDisplayInverseChanged) { layer.transformToDisplayInverse = proto.transform_to_display_inverse(); diff --git a/services/surfaceflinger/layerproto/transactions.proto b/services/surfaceflinger/layerproto/transactions.proto index b687abc918..4c6a9cf85b 100644 --- a/services/surfaceflinger/layerproto/transactions.proto +++ b/services/surfaceflinger/layerproto/transactions.proto @@ -98,8 +98,7 @@ message LayerState { eReparent = 0x00008000; eColorChanged = 0x00010000; - eDestroySurface = 0x00020000; - eTransformChanged = 0x00040000; + eBufferTransformChanged = 0x00040000; eTransformToDisplayInverseChanged = 0x00080000; eCropChanged = 0x00100000; -- cgit v1.2.3-59-g8ed1b From aa799bd679bc95810a623e8c1efebc5be1ad0659 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Wed, 16 Nov 2022 23:09:09 +0000 Subject: libgui: add layer_state_t::diff Compares two layer_state_t structs and returns a set of change flags describing all the states that are different. Also introduces change sets describing which set of client states can affect the hierarchy, content or the content size. Bug: 238781169 Test: presubmit Change-Id: I6e5fb255972aff2373be27e62005ee3a8de7ebf6 --- libs/gui/LayerState.cpp | 89 ++++++++++++++++++++++++++++++++++++++ libs/gui/SurfaceComposerClient.cpp | 1 + libs/gui/include/gui/LayerState.h | 30 +++++++++++++ 3 files changed, 120 insertions(+) (limited to 'libs/gui/LayerState.cpp') diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 924e65ec4a..95962afda1 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -24,10 +24,31 @@ #include #include #include +#include #include #include #include +#define CHECK_DIFF(DIFF_RESULT, CHANGE_FLAG, OTHER, FIELD) \ + { \ + if ((OTHER.what & CHANGE_FLAG) && (FIELD != OTHER.FIELD)) { \ + DIFF_RESULT |= CHANGE_FLAG; \ + } \ + } + +#define CHECK_DIFF2(DIFF_RESULT, CHANGE_FLAG, OTHER, FIELD1, FIELD2) \ + { \ + CHECK_DIFF(DIFF_RESULT, CHANGE_FLAG, OTHER, FIELD1) \ + CHECK_DIFF(DIFF_RESULT, CHANGE_FLAG, OTHER, FIELD2) \ + } + +#define CHECK_DIFF3(DIFF_RESULT, CHANGE_FLAG, OTHER, FIELD1, FIELD2, FIELD3) \ + { \ + CHECK_DIFF(DIFF_RESULT, CHANGE_FLAG, OTHER, FIELD1) \ + CHECK_DIFF(DIFF_RESULT, CHANGE_FLAG, OTHER, FIELD2) \ + CHECK_DIFF(DIFF_RESULT, CHANGE_FLAG, OTHER, FIELD3) \ + } + namespace android { using gui::FocusRequest; @@ -626,6 +647,74 @@ void layer_state_t::merge(const layer_state_t& other) { } } +uint64_t layer_state_t::diff(const layer_state_t& other) const { + uint64_t diff = 0; + CHECK_DIFF2(diff, ePositionChanged, other, x, y); + if (other.what & eLayerChanged) { + diff |= eLayerChanged; + diff &= ~eRelativeLayerChanged; + } + CHECK_DIFF(diff, eAlphaChanged, other, color.a); + CHECK_DIFF(diff, eMatrixChanged, other, matrix); + if (other.what & eTransparentRegionChanged && + (!transparentRegion.hasSameRects(other.transparentRegion))) { + diff |= eTransparentRegionChanged; + } + if (other.what & eFlagsChanged) { + uint64_t changedFlags = (flags & other.mask) ^ (other.flags & other.mask); + if (changedFlags) diff |= eFlagsChanged; + } + CHECK_DIFF(diff, eLayerStackChanged, other, layerStack); + CHECK_DIFF(diff, eCornerRadiusChanged, other, cornerRadius); + CHECK_DIFF(diff, eBackgroundBlurRadiusChanged, other, backgroundBlurRadius); + if (other.what & eBlurRegionsChanged) diff |= eBlurRegionsChanged; + if (other.what & eRelativeLayerChanged) { + diff |= eRelativeLayerChanged; + diff &= ~eLayerChanged; + } + if (other.what & eReparent && + !SurfaceControl::isSameSurface(parentSurfaceControlForChild, + other.parentSurfaceControlForChild)) { + diff |= eReparent; + } + CHECK_DIFF(diff, eBufferTransformChanged, other, bufferTransform); + CHECK_DIFF(diff, eTransformToDisplayInverseChanged, other, transformToDisplayInverse); + CHECK_DIFF(diff, eCropChanged, other, crop); + if (other.what & eBufferChanged) diff |= eBufferChanged; + CHECK_DIFF(diff, eDataspaceChanged, other, dataspace); + CHECK_DIFF(diff, eHdrMetadataChanged, other, hdrMetadata); + if (other.what & eSurfaceDamageRegionChanged && + (!surfaceDamageRegion.hasSameRects(other.surfaceDamageRegion))) { + diff |= eSurfaceDamageRegionChanged; + } + CHECK_DIFF(diff, eApiChanged, other, api); + if (other.what & eSidebandStreamChanged) diff |= eSidebandStreamChanged; + CHECK_DIFF(diff, eApiChanged, other, api); + CHECK_DIFF(diff, eColorTransformChanged, other, colorTransform); + if (other.what & eHasListenerCallbacksChanged) diff |= eHasListenerCallbacksChanged; + if (other.what & eInputInfoChanged) diff |= eInputInfoChanged; + CHECK_DIFF3(diff, eBackgroundColorChanged, other, color.rgb, bgColorAlpha, bgColorDataspace); + if (other.what & eMetadataChanged) diff |= eMetadataChanged; + CHECK_DIFF(diff, eShadowRadiusChanged, other, shadowRadius); + CHECK_DIFF3(diff, eRenderBorderChanged, other, borderEnabled, borderWidth, borderColor); + CHECK_DIFF(diff, eDefaultFrameRateCompatibilityChanged, other, defaultFrameRateCompatibility); + CHECK_DIFF(diff, eFrameRateSelectionPriority, other, frameRateSelectionPriority); + CHECK_DIFF3(diff, eFrameRateChanged, other, frameRate, frameRateCompatibility, + changeFrameRateStrategy); + CHECK_DIFF(diff, eFixedTransformHintChanged, other, fixedTransformHint); + CHECK_DIFF(diff, eAutoRefreshChanged, other, autoRefresh); + CHECK_DIFF(diff, eTrustedOverlayChanged, other, isTrustedOverlay); + CHECK_DIFF(diff, eStretchChanged, other, stretchEffect); + CHECK_DIFF(diff, eBufferCropChanged, other, bufferCrop); + CHECK_DIFF(diff, eDestinationFrameChanged, other, destinationFrame); + if (other.what & eProducerDisconnect) diff |= eProducerDisconnect; + CHECK_DIFF(diff, eDropInputModeChanged, other, dropInputMode); + CHECK_DIFF(diff, eColorChanged, other, color.rgb); + CHECK_DIFF(diff, eColorSpaceAgnosticChanged, other, colorSpaceAgnostic); + CHECK_DIFF(diff, eDimmingEnabledChanged, other, dimmingEnabled); + return diff; +} + bool layer_state_t::hasBufferChanges() const { return what & layer_state_t::eBufferChanged; } diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index d18d22d8ee..1e43700d06 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1250,6 +1250,7 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFlags 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)) { s->what |= layer_state_t::eFlagsChanged; } diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index 09f171db04..6ec6bd70db 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -201,7 +201,32 @@ struct layer_state_t { void merge(const layer_state_t& other); status_t write(Parcel& output) const; status_t read(const Parcel& input); + // Compares two layer_state_t structs and returns a set of change flags describing all the + // states that are different. + uint64_t diff(const layer_state_t& other) const; bool hasBufferChanges() const; + + // Changes to the tree structure. + static constexpr uint64_t HIERARCHY_CHANGES = layer_state_t::eLayerChanged | + layer_state_t::eRelativeLayerChanged | layer_state_t::eReparent | + layer_state_t::eBackgroundColorChanged; + // Content updates. + static constexpr uint64_t CONTENT_CHANGES = layer_state_t::eAlphaChanged | + layer_state_t::eTransparentRegionChanged | layer_state_t::eShadowRadiusChanged | + layer_state_t::eRenderBorderChanged | layer_state_t::eColorChanged | + layer_state_t::eBufferChanged | layer_state_t::eDataspaceChanged | + layer_state_t::eApiChanged | layer_state_t::eSidebandStreamChanged | + layer_state_t::eColorTransformChanged | layer_state_t::eCornerRadiusChanged | + layer_state_t::eBackgroundColorChanged | layer_state_t::eColorSpaceAgnosticChanged | + layer_state_t::eBackgroundBlurRadiusChanged | layer_state_t::eBlurRegionsChanged | + layer_state_t::eAutoRefreshChanged | layer_state_t::eStretchChanged; + // Changes to content or children size. + static constexpr uint64_t GEOMETRY_CHANGES = layer_state_t::ePositionChanged | + layer_state_t::eMatrixChanged | layer_state_t::eTransparentRegionChanged | + layer_state_t::eBufferCropChanged | layer_state_t::eBufferTransformChanged | + layer_state_t::eTransformToDisplayInverseChanged | layer_state_t::eCropChanged | + layer_state_t::eDestinationFrameChanged; + bool hasValidBuffer() const; void sanitize(int32_t permissions); @@ -212,6 +237,11 @@ struct layer_state_t { float dsdy{0}; status_t write(Parcel& output) const; status_t read(const Parcel& input); + inline bool operator==(const matrix22_t& other) const { + return std::tie(dsdx, dtdx, dtdy, dsdy) == + std::tie(other.dsdx, other.dtdx, other.dtdy, other.dsdy); + } + inline bool operator!=(const matrix22_t& other) const { return !(*this == other); } }; sp surface; int32_t layerId; -- cgit v1.2.3-59-g8ed1b From 6bb12824db3c540775b2b737331ed3f448a50e2e Mon Sep 17 00:00:00 2001 From: Sally Qi Date: Wed, 5 Oct 2022 11:42:30 -0700 Subject: Add security check to getPhysicalDisplayToken binder function. - There is a possible way to take over the screen display and swap the display content due to a missing permission check. - Add a short-term fix for WCG checking failure because of new permission check added to SF::getPhysicalDisplayToken: change two function signatures (getStaticDisplayInfo and getDynamicDisplayInfo). - To make short-term fix workable, split getDynamicDisplayInfo binder call into two, one is to take display id, one is to take display token as old codes show to avoid huge modification on other callees. Bug: 248031255 Test: test using displaytoken app manually on the phone, test shell screenrecord during using displaytoken; atest android.hardware.camera2.cts.FastBasicsTest Change-Id: Id9d9012d4ede9c8330f0ce1096bcb78e51b7c5df --- libs/gui/LayerState.cpp | 21 +++ libs/gui/SurfaceComposerClient.cpp | 117 +++++++----- libs/gui/aidl/android/gui/ISurfaceComposer.aidl | 6 +- libs/gui/fuzzer/libgui_fuzzer_utils.h | 6 +- libs/gui/include/gui/LayerState.h | 1 + libs/gui/include/gui/SurfaceComposerClient.h | 12 +- libs/gui/tests/Surface_test.cpp | 11 +- libs/nativedisplay/ADisplay.cpp | 23 +-- services/surfaceflinger/SurfaceFlinger.cpp | 200 ++++++++++++--------- services/surfaceflinger/SurfaceFlinger.h | 21 ++- .../fuzzer/surfaceflinger_fuzzers_utils.h | 18 +- services/surfaceflinger/tests/Credentials_test.cpp | 37 ++-- .../surfaceflinger/tests/DisplayConfigs_test.cpp | 6 +- .../SurfaceFlinger_ExcludeDolbyVisionTest.cpp | 6 +- .../tests/unittests/TestableSurfaceFlinger.h | 6 +- 15 files changed, 298 insertions(+), 193 deletions(-) (limited to 'libs/gui/LayerState.cpp') diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 95962afda1..59b62fe58c 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -388,6 +388,27 @@ void DisplayState::merge(const DisplayState& other) { } } +void DisplayState::sanitize(int32_t permissions) { + if (what & DisplayState::eLayerStackChanged) { + if (!(permissions & layer_state_t::Permission::ACCESS_SURFACE_FLINGER)) { + what &= ~DisplayState::eLayerStackChanged; + ALOGE("Stripped attempt to set eLayerStackChanged in sanitize"); + } + } + if (what & DisplayState::eDisplayProjectionChanged) { + if (!(permissions & layer_state_t::Permission::ACCESS_SURFACE_FLINGER)) { + what &= ~DisplayState::eDisplayProjectionChanged; + ALOGE("Stripped attempt to set eDisplayProjectionChanged in sanitize"); + } + } + if (what & DisplayState::eSurfaceChanged) { + if (!(permissions & layer_state_t::Permission::ACCESS_SURFACE_FLINGER)) { + what &= ~DisplayState::eSurfaceChanged; + ALOGE("Stripped attempt to set eSurfaceChanged in sanitize"); + } + } +} + void layer_state_t::sanitize(int32_t permissions) { // TODO: b/109894387 // diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 325c294762..abe5d35d0e 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -2260,12 +2260,12 @@ status_t SurfaceComposerClient::getDisplayState(const sp& display, return statusTFromBinderStatus(status); } -status_t SurfaceComposerClient::getStaticDisplayInfo(const sp& display, +status_t SurfaceComposerClient::getStaticDisplayInfo(int64_t displayId, ui::StaticDisplayInfo* outInfo) { using Tag = android::gui::DeviceProductInfo::ManufactureOrModelDate::Tag; gui::StaticDisplayInfo ginfo; binder::Status status = - ComposerServiceAIDL::getComposerService()->getStaticDisplayInfo(display, &ginfo); + ComposerServiceAIDL::getComposerService()->getStaticDisplayInfo(displayId, &ginfo); if (status.isOk()) { // convert gui::StaticDisplayInfo to ui::StaticDisplayInfo outInfo->connectionType = static_cast(ginfo.connectionType); @@ -2309,56 +2309,74 @@ status_t SurfaceComposerClient::getStaticDisplayInfo(const sp& display, return statusTFromBinderStatus(status); } -status_t SurfaceComposerClient::getDynamicDisplayInfo(const sp& display, - ui::DynamicDisplayInfo* outInfo) { +void SurfaceComposerClient::getDynamicDisplayInfoInternal(gui::DynamicDisplayInfo& ginfo, + ui::DynamicDisplayInfo*& outInfo) { + // convert gui::DynamicDisplayInfo to ui::DynamicDisplayInfo + outInfo->supportedDisplayModes.clear(); + outInfo->supportedDisplayModes.reserve(ginfo.supportedDisplayModes.size()); + for (const auto& mode : ginfo.supportedDisplayModes) { + ui::DisplayMode outMode; + outMode.id = mode.id; + outMode.resolution.width = mode.resolution.width; + outMode.resolution.height = mode.resolution.height; + outMode.xDpi = mode.xDpi; + outMode.yDpi = mode.yDpi; + outMode.refreshRate = mode.refreshRate; + outMode.appVsyncOffset = mode.appVsyncOffset; + outMode.sfVsyncOffset = mode.sfVsyncOffset; + outMode.presentationDeadline = mode.presentationDeadline; + outMode.group = mode.group; + std::transform(mode.supportedHdrTypes.begin(), mode.supportedHdrTypes.end(), + std::back_inserter(outMode.supportedHdrTypes), + [](const int32_t& value) { return static_cast(value); }); + outInfo->supportedDisplayModes.push_back(outMode); + } + + outInfo->activeDisplayModeId = ginfo.activeDisplayModeId; + outInfo->renderFrameRate = ginfo.renderFrameRate; + + outInfo->supportedColorModes.clear(); + outInfo->supportedColorModes.reserve(ginfo.supportedColorModes.size()); + for (const auto& cmode : ginfo.supportedColorModes) { + outInfo->supportedColorModes.push_back(static_cast(cmode)); + } + + outInfo->activeColorMode = static_cast(ginfo.activeColorMode); + + std::vector types; + types.reserve(ginfo.hdrCapabilities.supportedHdrTypes.size()); + for (const auto& hdr : ginfo.hdrCapabilities.supportedHdrTypes) { + types.push_back(static_cast(hdr)); + } + outInfo->hdrCapabilities = HdrCapabilities(types, ginfo.hdrCapabilities.maxLuminance, + ginfo.hdrCapabilities.maxAverageLuminance, + ginfo.hdrCapabilities.minLuminance); + + outInfo->autoLowLatencyModeSupported = ginfo.autoLowLatencyModeSupported; + outInfo->gameContentTypeSupported = ginfo.gameContentTypeSupported; + outInfo->preferredBootDisplayMode = ginfo.preferredBootDisplayMode; +} + +status_t SurfaceComposerClient::getDynamicDisplayInfoFromId(int64_t displayId, + ui::DynamicDisplayInfo* outInfo) { gui::DynamicDisplayInfo ginfo; binder::Status status = - ComposerServiceAIDL::getComposerService()->getDynamicDisplayInfo(display, &ginfo); + ComposerServiceAIDL::getComposerService()->getDynamicDisplayInfoFromId(displayId, + &ginfo); if (status.isOk()) { - // convert gui::DynamicDisplayInfo to ui::DynamicDisplayInfo - outInfo->supportedDisplayModes.clear(); - outInfo->supportedDisplayModes.reserve(ginfo.supportedDisplayModes.size()); - for (const auto& mode : ginfo.supportedDisplayModes) { - ui::DisplayMode outMode; - outMode.id = mode.id; - outMode.resolution.width = mode.resolution.width; - outMode.resolution.height = mode.resolution.height; - outMode.xDpi = mode.xDpi; - outMode.yDpi = mode.yDpi; - outMode.refreshRate = mode.refreshRate; - outMode.appVsyncOffset = mode.appVsyncOffset; - outMode.sfVsyncOffset = mode.sfVsyncOffset; - outMode.presentationDeadline = mode.presentationDeadline; - outMode.group = mode.group; - std::transform(mode.supportedHdrTypes.begin(), mode.supportedHdrTypes.end(), - std::back_inserter(outMode.supportedHdrTypes), - [](const int32_t& value) { return static_cast(value); }); - outInfo->supportedDisplayModes.push_back(outMode); - } - - outInfo->activeDisplayModeId = ginfo.activeDisplayModeId; - outInfo->renderFrameRate = ginfo.renderFrameRate; - - outInfo->supportedColorModes.clear(); - outInfo->supportedColorModes.reserve(ginfo.supportedColorModes.size()); - for (const auto& cmode : ginfo.supportedColorModes) { - outInfo->supportedColorModes.push_back(static_cast(cmode)); - } - - outInfo->activeColorMode = static_cast(ginfo.activeColorMode); - - std::vector types; - types.reserve(ginfo.hdrCapabilities.supportedHdrTypes.size()); - for (const auto& hdr : ginfo.hdrCapabilities.supportedHdrTypes) { - types.push_back(static_cast(hdr)); - } - outInfo->hdrCapabilities = HdrCapabilities(types, ginfo.hdrCapabilities.maxLuminance, - ginfo.hdrCapabilities.maxAverageLuminance, - ginfo.hdrCapabilities.minLuminance); + getDynamicDisplayInfoInternal(ginfo, outInfo); + } + return statusTFromBinderStatus(status); +} - outInfo->autoLowLatencyModeSupported = ginfo.autoLowLatencyModeSupported; - outInfo->gameContentTypeSupported = ginfo.gameContentTypeSupported; - outInfo->preferredBootDisplayMode = ginfo.preferredBootDisplayMode; +status_t SurfaceComposerClient::getDynamicDisplayInfoFromToken(const sp& display, + ui::DynamicDisplayInfo* outInfo) { + gui::DynamicDisplayInfo ginfo; + binder::Status status = + ComposerServiceAIDL::getComposerService()->getDynamicDisplayInfoFromToken(display, + &ginfo); + if (status.isOk()) { + getDynamicDisplayInfoInternal(ginfo, outInfo); } return statusTFromBinderStatus(status); } @@ -2366,7 +2384,8 @@ status_t SurfaceComposerClient::getDynamicDisplayInfo(const sp& display status_t SurfaceComposerClient::getActiveDisplayMode(const sp& display, ui::DisplayMode* mode) { ui::DynamicDisplayInfo info; - status_t result = getDynamicDisplayInfo(display, &info); + + status_t result = getDynamicDisplayInfoFromToken(display, &info); if (result != NO_ERROR) { return result; } diff --git a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl index 40410fb59e..488a1486cc 100644 --- a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl +++ b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl @@ -126,12 +126,14 @@ interface ISurfaceComposer { /** * Gets immutable information about given physical display. */ - StaticDisplayInfo getStaticDisplayInfo(IBinder display); + StaticDisplayInfo getStaticDisplayInfo(long displayId); /** * Gets dynamic information about given physical display. */ - DynamicDisplayInfo getDynamicDisplayInfo(IBinder display); + DynamicDisplayInfo getDynamicDisplayInfoFromId(long displayId); + + DynamicDisplayInfo getDynamicDisplayInfoFromToken(IBinder display); DisplayPrimaries getDisplayNativePrimaries(IBinder display); diff --git a/libs/gui/fuzzer/libgui_fuzzer_utils.h b/libs/gui/fuzzer/libgui_fuzzer_utils.h index 9d1ee8f65b..8810e4e83a 100644 --- a/libs/gui/fuzzer/libgui_fuzzer_utils.h +++ b/libs/gui/fuzzer/libgui_fuzzer_utils.h @@ -79,9 +79,11 @@ public: (override)); MOCK_METHOD(binder::Status, getDisplayState, (const sp&, gui::DisplayState*), (override)); - MOCK_METHOD(binder::Status, getStaticDisplayInfo, (const sp&, gui::StaticDisplayInfo*), + MOCK_METHOD(binder::Status, getStaticDisplayInfo, (int64_t, gui::StaticDisplayInfo*), (override)); - MOCK_METHOD(binder::Status, getDynamicDisplayInfo, + MOCK_METHOD(binder::Status, getDynamicDisplayInfoFromId, (int64_t, gui::DynamicDisplayInfo*), + (override)); + MOCK_METHOD(binder::Status, getDynamicDisplayInfoFromToken, (const sp&, gui::DynamicDisplayInfo*), (override)); MOCK_METHOD(binder::Status, getDisplayNativePrimaries, (const sp&, gui::DisplayPrimaries*), (override)); diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index 6ec6bd70db..45a84f6c66 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -359,6 +359,7 @@ struct DisplayState { DisplayState(); void merge(const DisplayState& other); + void sanitize(int32_t permissions); uint32_t what = 0; uint32_t flags = 0; diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 2038f1477a..df47002b3b 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -149,10 +149,10 @@ public: static status_t getDisplayState(const sp& display, ui::DisplayState*); // Get immutable information about given physical display. - static status_t getStaticDisplayInfo(const sp& display, ui::StaticDisplayInfo*); + static status_t getStaticDisplayInfo(int64_t, ui::StaticDisplayInfo*); - // Get dynamic information about given physical display. - static status_t getDynamicDisplayInfo(const sp& display, ui::DynamicDisplayInfo*); + // Get dynamic information about given physical display from display id + static status_t getDynamicDisplayInfoFromId(int64_t, ui::DynamicDisplayInfo*); // Shorthand for the active display mode from getDynamicDisplayInfo(). // TODO(b/180391891): Update clients to use getDynamicDisplayInfo and remove this function. @@ -714,6 +714,12 @@ protected: ReleaseCallbackThread mReleaseCallbackThread; private: + // Get dynamic information about given physical display from token + static status_t getDynamicDisplayInfoFromToken(const sp& display, + ui::DynamicDisplayInfo*); + + static void getDynamicDisplayInfoInternal(gui::DynamicDisplayInfo& ginfo, + ui::DynamicDisplayInfo*& outInfo); virtual void onFirstRef(); mutable Mutex mLock; diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 6d3b42515b..55242dfd39 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -782,13 +782,18 @@ public: return binder::Status::ok(); } - binder::Status getStaticDisplayInfo(const sp& /*display*/, + binder::Status getStaticDisplayInfo(int64_t /*displayId*/, gui::StaticDisplayInfo* /*outInfo*/) override { return binder::Status::ok(); } - binder::Status getDynamicDisplayInfo(const sp& /*display*/, - gui::DynamicDisplayInfo* /*outInfo*/) override { + binder::Status getDynamicDisplayInfoFromId(int64_t /*displayId*/, + gui::DynamicDisplayInfo* /*outInfo*/) override { + return binder::Status::ok(); + } + + binder::Status getDynamicDisplayInfoFromToken(const sp& /*display*/, + gui::DynamicDisplayInfo* /*outInfo*/) override { return binder::Status::ok(); } diff --git a/libs/nativedisplay/ADisplay.cpp b/libs/nativedisplay/ADisplay.cpp index 60328e48a6..bf0805b46c 100644 --- a/libs/nativedisplay/ADisplay.cpp +++ b/libs/nativedisplay/ADisplay.cpp @@ -117,15 +117,6 @@ using namespace android::display::impl; #define CHECK_NOT_NULL(name) \ LOG_ALWAYS_FATAL_IF(name == nullptr, "nullptr passed as " #name " argument"); -namespace { - -sp getToken(ADisplay* display) { - DisplayImpl* impl = reinterpret_cast(display); - return SurfaceComposerClient::getPhysicalDisplayToken(impl->id); -} - -} // namespace - namespace android { int ADisplay_acquirePhysicalDisplays(ADisplay*** outDisplays) { @@ -139,10 +130,9 @@ int ADisplay_acquirePhysicalDisplays(ADisplay*** outDisplays) { ui::DisplayConnectionType displayConnectionTypes[size]; int numModes = 0; for (int i = 0; i < size; ++i) { - const sp token = SurfaceComposerClient::getPhysicalDisplayToken(ids[i]); - ui::StaticDisplayInfo staticInfo; - if (const status_t status = SurfaceComposerClient::getStaticDisplayInfo(token, &staticInfo); + if (const status_t status = + SurfaceComposerClient::getStaticDisplayInfo(ids[i].value, &staticInfo); status != OK) { return status; } @@ -150,7 +140,7 @@ int ADisplay_acquirePhysicalDisplays(ADisplay*** outDisplays) { ui::DynamicDisplayInfo dynamicInfo; if (const status_t status = - SurfaceComposerClient::getDynamicDisplayInfo(token, &dynamicInfo); + SurfaceComposerClient::getDynamicDisplayInfoFromId(ids[i].value, &dynamicInfo); status != OK) { return status; } @@ -260,14 +250,15 @@ void ADisplay_getPreferredWideColorFormat(ADisplay* display, ADataSpace* outData int ADisplay_getCurrentConfig(ADisplay* display, ADisplayConfig** outConfig) { CHECK_NOT_NULL(display); - sp token = getToken(display); ui::DynamicDisplayInfo info; - if (const auto status = SurfaceComposerClient::getDynamicDisplayInfo(token, &info); + DisplayImpl* impl = reinterpret_cast(display); + + if (const auto status = + SurfaceComposerClient::getDynamicDisplayInfoFromId(impl->id.value, &info); status != OK) { return status; } - DisplayImpl* impl = reinterpret_cast(display); for (size_t i = 0; i < impl->numConfigs; i++) { auto* config = impl->configs + i; if (config->id == info.activeDisplayModeId) { diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 36ff3ec5c2..6da6022a83 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -974,17 +974,14 @@ status_t SurfaceFlinger::getDisplayState(const sp& displayToken, ui::Di return NO_ERROR; } -status_t SurfaceFlinger::getStaticDisplayInfo(const sp& displayToken, - ui::StaticDisplayInfo* info) { - if (!displayToken || !info) { +status_t SurfaceFlinger::getStaticDisplayInfo(int64_t displayId, ui::StaticDisplayInfo* info) { + if (!info) { return BAD_VALUE; } Mutex::Autolock lock(mStateLock); - - const auto displayOpt = ftl::find_if(mPhysicalDisplays, PhysicalDisplay::hasToken(displayToken)) - .transform(&ftl::to_mapped_ref) - .and_then(getDisplayDeviceAndSnapshot()); + const auto id = DisplayId::fromValue(static_cast(displayId)); + const auto displayOpt = mPhysicalDisplays.get(*id).and_then(getDisplayDeviceAndSnapshot()); if (!displayOpt) { return NAME_NOT_FOUND; @@ -1011,26 +1008,10 @@ status_t SurfaceFlinger::getStaticDisplayInfo(const sp& displayToken, return NO_ERROR; } -status_t SurfaceFlinger::getDynamicDisplayInfo(const sp& displayToken, - ui::DynamicDisplayInfo* info) { - if (!displayToken || !info) { - return BAD_VALUE; - } - - Mutex::Autolock lock(mStateLock); - - const auto displayOpt = ftl::find_if(mPhysicalDisplays, PhysicalDisplay::hasToken(displayToken)) - .transform(&ftl::to_mapped_ref) - .and_then(getDisplayDeviceAndSnapshot()); - if (!displayOpt) { - return NAME_NOT_FOUND; - } - - const auto& [display, snapshotRef] = *displayOpt; - const auto& snapshot = snapshotRef.get(); - +void SurfaceFlinger::getDynamicDisplayInfoInternal(ui::DynamicDisplayInfo*& info, + const sp& display, + const display::DisplaySnapshot& snapshot) { const auto& displayModes = snapshot.displayModes(); - info->supportedDisplayModes.clear(); info->supportedDisplayModes.reserve(displayModes.size()); @@ -1104,7 +1085,47 @@ status_t SurfaceFlinger::getDynamicDisplayInfo(const sp& displayToken, } } } +} + +status_t SurfaceFlinger::getDynamicDisplayInfoFromId(int64_t physicalDisplayId, + ui::DynamicDisplayInfo* info) { + if (!info) { + return BAD_VALUE; + } + + Mutex::Autolock lock(mStateLock); + + const auto id_ = + DisplayId::fromValue(static_cast(physicalDisplayId)); + const auto displayOpt = mPhysicalDisplays.get(*id_).and_then(getDisplayDeviceAndSnapshot()); + + if (!displayOpt) { + return NAME_NOT_FOUND; + } + + const auto& [display, snapshotRef] = *displayOpt; + getDynamicDisplayInfoInternal(info, display, snapshotRef.get()); + return NO_ERROR; +} + +status_t SurfaceFlinger::getDynamicDisplayInfoFromToken(const sp& displayToken, + ui::DynamicDisplayInfo* info) { + if (!displayToken || !info) { + return BAD_VALUE; + } + + Mutex::Autolock lock(mStateLock); + + const auto displayOpt = ftl::find_if(mPhysicalDisplays, PhysicalDisplay::hasToken(displayToken)) + .transform(&ftl::to_mapped_ref) + .and_then(getDisplayDeviceAndSnapshot()); + + if (!displayOpt) { + return NAME_NOT_FOUND; + } + const auto& [display, snapshotRef] = *displayOpt; + getDynamicDisplayInfoInternal(info, display, snapshotRef.get()); return NO_ERROR; } @@ -4036,7 +4057,7 @@ status_t SurfaceFlinger::setTransactionState( bool SurfaceFlinger::applyTransactionState(const FrameTimelineInfo& frameTimelineInfo, std::vector& states, - const Vector& displays, uint32_t flags, + Vector& displays, uint32_t flags, const InputWindowCommands& inputWindowCommands, const int64_t desiredPresentTime, bool isAutoTimestamp, const client_cache_t& uncacheBuffer, @@ -4045,7 +4066,8 @@ bool SurfaceFlinger::applyTransactionState(const FrameTimelineInfo& frameTimelin const std::vector& listenerCallbacks, int originPid, int originUid, uint64_t transactionId) { uint32_t transactionFlags = 0; - for (const DisplayState& display : displays) { + for (DisplayState& display : displays) { + display.sanitize(permissions); transactionFlags |= setDisplayStateLocked(display); } @@ -7283,6 +7305,10 @@ binder::Status SurfaceComposerAIDL::getPhysicalDisplayIds(std::vector* binder::Status SurfaceComposerAIDL::getPhysicalDisplayToken(int64_t displayId, sp* outDisplay) { + status_t status = checkAccessPermission(); + if (status != OK) { + return binderStatusFromStatusT(status); + } const auto id = DisplayId::fromValue(static_cast(displayId)); *outDisplay = mFlinger->getPhysicalDisplayToken(*id); return binder::Status::ok(); @@ -7333,11 +7359,12 @@ binder::Status SurfaceComposerAIDL::getDisplayState(const sp& display, return binderStatusFromStatusT(status); } -binder::Status SurfaceComposerAIDL::getStaticDisplayInfo(const sp& display, +binder::Status SurfaceComposerAIDL::getStaticDisplayInfo(int64_t displayId, gui::StaticDisplayInfo* outInfo) { using Tag = gui::DeviceProductInfo::ManufactureOrModelDate::Tag; ui::StaticDisplayInfo info; - status_t status = mFlinger->getStaticDisplayInfo(display, &info); + + status_t status = mFlinger->getStaticDisplayInfo(displayId, &info); if (status == NO_ERROR) { // convert ui::StaticDisplayInfo to gui::StaticDisplayInfo outInfo->connectionType = static_cast(info.connectionType); @@ -7376,58 +7403,71 @@ binder::Status SurfaceComposerAIDL::getStaticDisplayInfo(const sp& disp return binderStatusFromStatusT(status); } -binder::Status SurfaceComposerAIDL::getDynamicDisplayInfo(const sp& display, - gui::DynamicDisplayInfo* outInfo) { +void SurfaceComposerAIDL::getDynamicDisplayInfoInternal(ui::DynamicDisplayInfo& info, + gui::DynamicDisplayInfo*& outInfo) { + // convert ui::DynamicDisplayInfo to gui::DynamicDisplayInfo + outInfo->supportedDisplayModes.clear(); + outInfo->supportedDisplayModes.reserve(info.supportedDisplayModes.size()); + for (const auto& mode : info.supportedDisplayModes) { + gui::DisplayMode outMode; + outMode.id = mode.id; + outMode.resolution.width = mode.resolution.width; + outMode.resolution.height = mode.resolution.height; + outMode.xDpi = mode.xDpi; + outMode.yDpi = mode.yDpi; + outMode.refreshRate = mode.refreshRate; + outMode.appVsyncOffset = mode.appVsyncOffset; + outMode.sfVsyncOffset = mode.sfVsyncOffset; + outMode.presentationDeadline = mode.presentationDeadline; + outMode.group = mode.group; + std::transform(mode.supportedHdrTypes.begin(), mode.supportedHdrTypes.end(), + std::back_inserter(outMode.supportedHdrTypes), + [](const ui::Hdr& value) { return static_cast(value); }); + outInfo->supportedDisplayModes.push_back(outMode); + } + + outInfo->activeDisplayModeId = info.activeDisplayModeId; + outInfo->renderFrameRate = info.renderFrameRate; + + outInfo->supportedColorModes.clear(); + outInfo->supportedColorModes.reserve(info.supportedColorModes.size()); + for (const auto& cmode : info.supportedColorModes) { + outInfo->supportedColorModes.push_back(static_cast(cmode)); + } + + outInfo->activeColorMode = static_cast(info.activeColorMode); + + gui::HdrCapabilities& hdrCapabilities = outInfo->hdrCapabilities; + hdrCapabilities.supportedHdrTypes.clear(); + hdrCapabilities.supportedHdrTypes.reserve(info.hdrCapabilities.getSupportedHdrTypes().size()); + for (const auto& hdr : info.hdrCapabilities.getSupportedHdrTypes()) { + hdrCapabilities.supportedHdrTypes.push_back(static_cast(hdr)); + } + hdrCapabilities.maxLuminance = info.hdrCapabilities.getDesiredMaxLuminance(); + hdrCapabilities.maxAverageLuminance = info.hdrCapabilities.getDesiredMaxAverageLuminance(); + hdrCapabilities.minLuminance = info.hdrCapabilities.getDesiredMinLuminance(); + + outInfo->autoLowLatencyModeSupported = info.autoLowLatencyModeSupported; + outInfo->gameContentTypeSupported = info.gameContentTypeSupported; + outInfo->preferredBootDisplayMode = info.preferredBootDisplayMode; +} + +binder::Status SurfaceComposerAIDL::getDynamicDisplayInfoFromToken( + const sp& display, gui::DynamicDisplayInfo* outInfo) { + ui::DynamicDisplayInfo info; + status_t status = mFlinger->getDynamicDisplayInfoFromToken(display, &info); + if (status == NO_ERROR) { + getDynamicDisplayInfoInternal(info, outInfo); + } + return binderStatusFromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::getDynamicDisplayInfoFromId(int64_t displayId, + gui::DynamicDisplayInfo* outInfo) { ui::DynamicDisplayInfo info; - status_t status = mFlinger->getDynamicDisplayInfo(display, &info); + status_t status = mFlinger->getDynamicDisplayInfoFromId(displayId, &info); if (status == NO_ERROR) { - // convert ui::DynamicDisplayInfo to gui::DynamicDisplayInfo - outInfo->supportedDisplayModes.clear(); - outInfo->supportedDisplayModes.reserve(info.supportedDisplayModes.size()); - for (const auto& mode : info.supportedDisplayModes) { - gui::DisplayMode outMode; - outMode.id = mode.id; - outMode.resolution.width = mode.resolution.width; - outMode.resolution.height = mode.resolution.height; - outMode.xDpi = mode.xDpi; - outMode.yDpi = mode.yDpi; - outMode.refreshRate = mode.refreshRate; - outMode.appVsyncOffset = mode.appVsyncOffset; - outMode.sfVsyncOffset = mode.sfVsyncOffset; - outMode.presentationDeadline = mode.presentationDeadline; - outMode.group = mode.group; - std::transform(mode.supportedHdrTypes.begin(), mode.supportedHdrTypes.end(), - std::back_inserter(outMode.supportedHdrTypes), - [](const ui::Hdr& value) { return static_cast(value); }); - - outInfo->supportedDisplayModes.push_back(outMode); - } - - outInfo->activeDisplayModeId = info.activeDisplayModeId; - outInfo->renderFrameRate = info.renderFrameRate; - - outInfo->supportedColorModes.clear(); - outInfo->supportedColorModes.reserve(info.supportedColorModes.size()); - for (const auto& cmode : info.supportedColorModes) { - outInfo->supportedColorModes.push_back(static_cast(cmode)); - } - - outInfo->activeColorMode = static_cast(info.activeColorMode); - - gui::HdrCapabilities& hdrCapabilities = outInfo->hdrCapabilities; - hdrCapabilities.supportedHdrTypes.clear(); - hdrCapabilities.supportedHdrTypes.reserve( - info.hdrCapabilities.getSupportedHdrTypes().size()); - for (const auto& hdr : info.hdrCapabilities.getSupportedHdrTypes()) { - hdrCapabilities.supportedHdrTypes.push_back(static_cast(hdr)); - } - hdrCapabilities.maxLuminance = info.hdrCapabilities.getDesiredMaxLuminance(); - hdrCapabilities.maxAverageLuminance = info.hdrCapabilities.getDesiredMaxAverageLuminance(); - hdrCapabilities.minLuminance = info.hdrCapabilities.getDesiredMinLuminance(); - - outInfo->autoLowLatencyModeSupported = info.autoLowLatencyModeSupported; - outInfo->gameContentTypeSupported = info.gameContentTypeSupported; - outInfo->preferredBootDisplayMode = info.preferredBootDisplayMode; + getDynamicDisplayInfoInternal(info, outInfo); } return binderStatusFromStatusT(status); } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 6ddcfbccf8..e265939e70 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -512,10 +512,13 @@ private: status_t getDisplayStats(const sp& displayToken, DisplayStatInfo* stats); status_t getDisplayState(const sp& displayToken, ui::DisplayState*) EXCLUDES(mStateLock); - status_t getStaticDisplayInfo(const sp& displayToken, ui::StaticDisplayInfo*) - EXCLUDES(mStateLock); - status_t getDynamicDisplayInfo(const sp& displayToken, ui::DynamicDisplayInfo*) + status_t getStaticDisplayInfo(int64_t displayId, ui::StaticDisplayInfo*) EXCLUDES(mStateLock); + status_t getDynamicDisplayInfoFromId(int64_t displayId, ui::DynamicDisplayInfo*) EXCLUDES(mStateLock); + status_t getDynamicDisplayInfoFromToken(const sp& displayToken, + ui::DynamicDisplayInfo*) EXCLUDES(mStateLock); + void getDynamicDisplayInfoInternal(ui::DynamicDisplayInfo*&, const sp&, + const display::DisplaySnapshot&); status_t getDisplayNativePrimaries(const sp& displayToken, ui::DisplayPrimaries&); status_t setActiveColorMode(const sp& displayToken, ui::ColorMode colorMode); status_t getBootDisplayModeSupport(bool* outSupport) const; @@ -702,7 +705,7 @@ private: */ bool applyTransactionState(const FrameTimelineInfo& info, std::vector& state, - const Vector& displays, uint32_t flags, + Vector& displays, uint32_t flags, const InputWindowCommands& inputWindowCommands, const int64_t desiredPresentTime, bool isAutoTimestamp, const client_cache_t& uncacheBuffer, const int64_t postTime, @@ -1401,10 +1404,12 @@ public: gui::DisplayStatInfo* outStatInfo) override; binder::Status getDisplayState(const sp& display, gui::DisplayState* outState) override; - binder::Status getStaticDisplayInfo(const sp& display, + binder::Status getStaticDisplayInfo(int64_t displayId, gui::StaticDisplayInfo* outInfo) override; - binder::Status getDynamicDisplayInfo(const sp& display, - gui::DynamicDisplayInfo* outInfo) override; + binder::Status getDynamicDisplayInfoFromId(int64_t displayId, + gui::DynamicDisplayInfo* outInfo) override; + binder::Status getDynamicDisplayInfoFromToken(const sp& display, + gui::DynamicDisplayInfo* outInfo) override; binder::Status getDisplayNativePrimaries(const sp& display, gui::DisplayPrimaries* outPrimaries) override; binder::Status setActiveColorMode(const sp& display, int colorMode) override; @@ -1489,6 +1494,8 @@ private: status_t checkAccessPermission(bool usePermissionCache = kUsePermissionCache); status_t checkControlDisplayBrightnessPermission(); status_t checkReadFrameBufferPermission(); + static void getDynamicDisplayInfoInternal(ui::DynamicDisplayInfo& info, + gui::DynamicDisplayInfo*& outInfo); private: sp mFlinger; diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h index c0a6bdbe27..96844d2b18 100644 --- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h +++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h @@ -491,14 +491,14 @@ public: mFlinger->getDisplayState(display, &displayState); } - void getStaticDisplayInfo(sp &display) { + void getStaticDisplayInfo(int64_t displayId) { ui::StaticDisplayInfo staticDisplayInfo; - mFlinger->getStaticDisplayInfo(display, &staticDisplayInfo); + mFlinger->getStaticDisplayInfo(displayId, &staticDisplayInfo); } - void getDynamicDisplayInfo(sp &display) { + void getDynamicDisplayInfo(int64_t displayId) { android::ui::DynamicDisplayInfo dynamicDisplayInfo; - mFlinger->getDynamicDisplayInfo(display, &dynamicDisplayInfo); + mFlinger->getDynamicDisplayInfoFromId(displayId, &dynamicDisplayInfo); } void getDisplayNativePrimaries(sp &display) { android::ui::DisplayPrimaries displayPrimaries; @@ -522,7 +522,7 @@ public: return ids.front(); } - sp fuzzBoot(FuzzedDataProvider *fdp) { + std::pair, int64_t> fuzzBoot(FuzzedDataProvider *fdp) { mFlinger->callingThreadHasUnscopedSurfaceFlingerAccess(fdp->ConsumeBool()); const sp client = sp::make(mFlinger); @@ -549,13 +549,13 @@ public: mFlinger->bootFinished(); - return display; + return {display, physicalDisplayId.value}; } void fuzzSurfaceFlinger(const uint8_t *data, size_t size) { FuzzedDataProvider mFdp(data, size); - sp display = fuzzBoot(&mFdp); + auto [display, displayId] = fuzzBoot(&mFdp); sp bufferProducer = sp::make(); @@ -563,8 +563,8 @@ public: getDisplayStats(display); getDisplayState(display); - getStaticDisplayInfo(display); - getDynamicDisplayInfo(display); + getStaticDisplayInfo(displayId); + getDynamicDisplayInfo(displayId); getDisplayNativePrimaries(display); mFlinger->setAutoLowLatencyMode(display, mFdp.ConsumeBool()); diff --git a/services/surfaceflinger/tests/Credentials_test.cpp b/services/surfaceflinger/tests/Credentials_test.cpp index 16768441f0..4a45eb5586 100644 --- a/services/surfaceflinger/tests/Credentials_test.cpp +++ b/services/surfaceflinger/tests/Credentials_test.cpp @@ -83,6 +83,15 @@ protected: return SurfaceComposerClient::getPhysicalDisplayToken(ids.front()); } + static std::optional getFirstDisplayId() { + const auto ids = SurfaceComposerClient::getPhysicalDisplayIds(); + if (ids.empty()) { + return std::nullopt; + } + + return ids.front().value; + } + void setupBackgroundSurface() { mDisplay = getFirstDisplayToken(); ASSERT_FALSE(mDisplay == nullptr); @@ -169,29 +178,25 @@ TEST_F(CredentialsTest, ClientInitTest) { TEST_F(CredentialsTest, GetBuiltInDisplayAccessTest) { std::function condition = [] { return getFirstDisplayToken() != nullptr; }; // Anyone can access display information. - ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, true, true)); + ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, true, false)); } TEST_F(CredentialsTest, AllowedGetterMethodsTest) { // The following methods are tested with a UID that is not root, graphics, // or system, to show that anyone can access them. UIDFaker f(AID_BIN); - const auto display = getFirstDisplayToken(); - ASSERT_TRUE(display != nullptr); - - ui::DisplayMode mode; - ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayMode(display, &mode)); - - Vector modes; + const auto id = getFirstDisplayId(); + ASSERT_TRUE(id); ui::DynamicDisplayInfo info; - ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDynamicDisplayInfo(display, &info)); + ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDynamicDisplayInfoFromId(*id, &info)); } TEST_F(CredentialsTest, GetDynamicDisplayInfoTest) { - const auto display = getFirstDisplayToken(); + const auto id = getFirstDisplayId(); + ASSERT_TRUE(id); std::function condition = [=]() { ui::DynamicDisplayInfo info; - return SurfaceComposerClient::getDynamicDisplayInfo(display, &info); + return SurfaceComposerClient::getDynamicDisplayInfoFromId(*id, &info); }; ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, NO_ERROR, NO_ERROR)); } @@ -335,8 +340,10 @@ TEST_F(CredentialsTest, IsWideColorDisplayBasicCorrectness) { status_t error = SurfaceComposerClient::isWideColorDisplay(display, &result); ASSERT_EQ(NO_ERROR, error); bool hasWideColorMode = false; + const auto id = getFirstDisplayId(); + ASSERT_TRUE(id); ui::DynamicDisplayInfo info; - SurfaceComposerClient::getDynamicDisplayInfo(display, &info); + SurfaceComposerClient::getDynamicDisplayInfoFromId(*id, &info); const auto& colorModes = info.supportedColorModes; for (ColorMode colorMode : colorModes) { switch (colorMode) { @@ -363,10 +370,10 @@ TEST_F(CredentialsTest, IsWideColorDisplayWithPrivileges) { } TEST_F(CredentialsTest, GetActiveColorModeBasicCorrectness) { - const auto display = getFirstDisplayToken(); - ASSERT_FALSE(display == nullptr); + const auto id = getFirstDisplayId(); + ASSERT_TRUE(id); ui::DynamicDisplayInfo info; - SurfaceComposerClient::getDynamicDisplayInfo(display, &info); + SurfaceComposerClient::getDynamicDisplayInfoFromId(*id, &info); ColorMode colorMode = info.activeColorMode; ASSERT_NE(static_cast(BAD_VALUE), colorMode); } diff --git a/services/surfaceflinger/tests/DisplayConfigs_test.cpp b/services/surfaceflinger/tests/DisplayConfigs_test.cpp index 10dae4636e..4be961bda1 100644 --- a/services/surfaceflinger/tests/DisplayConfigs_test.cpp +++ b/services/surfaceflinger/tests/DisplayConfigs_test.cpp @@ -45,6 +45,7 @@ protected: void SetUp() override { const auto ids = SurfaceComposerClient::getPhysicalDisplayIds(); ASSERT_FALSE(ids.empty()); + mDisplayId = ids.front().value; mDisplayToken = SurfaceComposerClient::getPhysicalDisplayToken(ids.front()); status_t res = SurfaceComposerClient::getDesiredDisplayModeSpecs(mDisplayToken, &mSpecs); ASSERT_EQ(res, NO_ERROR); @@ -58,11 +59,14 @@ protected: void testSetAllowGroupSwitching(bool allowGroupSwitching); sp mDisplayToken; + uint64_t mDisplayId; }; TEST_F(RefreshRateRangeTest, setAllConfigs) { ui::DynamicDisplayInfo info; - status_t res = SurfaceComposerClient::getDynamicDisplayInfo(mDisplayToken, &info); + status_t res = + SurfaceComposerClient::getDynamicDisplayInfoFromId(static_cast(mDisplayId), + &info); const auto& modes = info.supportedDisplayModes; ASSERT_EQ(res, NO_ERROR); ASSERT_GT(modes.size(), 0); diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_ExcludeDolbyVisionTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_ExcludeDolbyVisionTest.cpp index 11e734a416..0e149d2bfb 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_ExcludeDolbyVisionTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_ExcludeDolbyVisionTest.cpp @@ -61,7 +61,7 @@ protected: TEST_F(ExcludeDolbyVisionTest, excludesDolbyVisionOnModesHigherThan4k30) { injectDisplayModes({mode4k60}); ui::DynamicDisplayInfo info; - mFlinger.getDynamicDisplayInfo(mDisplay->getDisplayToken().promote(), &info); + mFlinger.getDynamicDisplayInfoFromToken(mDisplay->getDisplayToken().promote(), &info); std::vector displayModes = info.supportedDisplayModes; @@ -75,7 +75,7 @@ TEST_F(ExcludeDolbyVisionTest, excludesDolbyVisionOnModesHigherThan4k30) { TEST_F(ExcludeDolbyVisionTest, includesDolbyVisionOnModesLowerThanOrEqualTo4k30) { injectDisplayModes({mode1080p60, mode4k30, mode4k30NonStandard}); ui::DynamicDisplayInfo info; - mFlinger.getDynamicDisplayInfo(mDisplay->getDisplayToken().promote(), &info); + mFlinger.getDynamicDisplayInfoFromToken(mDisplay->getDisplayToken().promote(), &info); std::vector displayModes = info.supportedDisplayModes; @@ -94,7 +94,7 @@ TEST_F(ExcludeDolbyVisionTest, includesDolbyVisionOnModesLowerThanOrEqualTo4k30) TEST_F(ExcludeDolbyVisionTest, 4k30IsNotReportedAsAValidHdrType) { injectDisplayModes({mode4k60}); ui::DynamicDisplayInfo info; - mFlinger.getDynamicDisplayInfo(mDisplay->getDisplayToken().promote(), &info); + mFlinger.getDynamicDisplayInfoFromToken(mDisplay->getDisplayToken().promote(), &info); std::vector displayHdrTypes = info.hdrCapabilities.getSupportedHdrTypes(); diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 7d0b340cfa..2117084bbf 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -487,9 +487,9 @@ public: void updateLayerMetadataSnapshot() { mFlinger->updateLayerMetadataSnapshot(); } - void getDynamicDisplayInfo(const sp& displayToken, - ui::DynamicDisplayInfo* dynamicDisplayInfo) { - mFlinger->getDynamicDisplayInfo(displayToken, dynamicDisplayInfo); + void getDynamicDisplayInfoFromToken(const sp& displayToken, + ui::DynamicDisplayInfo* dynamicDisplayInfo) { + mFlinger->getDynamicDisplayInfoFromToken(displayToken, dynamicDisplayInfo); } /* ------------------------------------------------------------------------ -- cgit v1.2.3-59-g8ed1b From c50b4988e93872bfe023a4e099548f84bdfd998d Mon Sep 17 00:00:00 2001 From: Huihong Luo Date: Wed, 24 Nov 2021 12:34:52 -0800 Subject: Migrate ITransactionCompletedListener to AIDL This migrates the c++ interface to aidl. Bug: 225250470 Test: atest libsurfaceflinger_unittest libgui_test SurfaceFlinger_test Change-Id: I997e302ac8c6a23bedefaa5b8272677f3dce54df --- libs/binder/include/binder/IInterface.h | 1 - libs/gui/ISurfaceComposer.cpp | 1 + libs/gui/ITransactionCompletedListener.cpp | 71 +----- libs/gui/LayerState.cpp | 1 + libs/gui/SurfaceComposerClient.cpp | 33 ++- .../android/gui/ITransactionCompletedListener.aidl | 31 +++ libs/gui/aidl/android/gui/ListenerStats.aidl | 19 ++ libs/gui/aidl/android/gui/ReleaseCallbackId.aidl | 19 ++ libs/gui/include/gui/ISurfaceComposer.h | 3 +- .../include/gui/ITransactionCompletedListener.h | 271 --------------------- libs/gui/include/gui/LayerState.h | 6 +- libs/gui/include/gui/ListenerStats.h | 225 +++++++++++++++++ libs/gui/include/gui/ReleaseCallbackId.h | 50 ++++ libs/gui/include/gui/SurfaceComposerClient.h | 25 +- .../surfaceflinger/FrontEnd/TransactionHandler.cpp | 2 +- .../surfaceflinger/FrontEnd/TransactionHandler.h | 1 + services/surfaceflinger/Layer.cpp | 9 +- services/surfaceflinger/SurfaceFlinger.cpp | 5 +- services/surfaceflinger/SurfaceFlinger.h | 5 +- .../surfaceflinger/TransactionCallbackInvoker.h | 17 +- 20 files changed, 428 insertions(+), 367 deletions(-) create mode 100644 libs/gui/aidl/android/gui/ITransactionCompletedListener.aidl create mode 100644 libs/gui/aidl/android/gui/ListenerStats.aidl create mode 100644 libs/gui/aidl/android/gui/ReleaseCallbackId.aidl delete mode 100644 libs/gui/include/gui/ITransactionCompletedListener.h create mode 100644 libs/gui/include/gui/ListenerStats.h create mode 100644 libs/gui/include/gui/ReleaseCallbackId.h (limited to 'libs/gui/LayerState.cpp') diff --git a/libs/binder/include/binder/IInterface.h b/libs/binder/include/binder/IInterface.h index dc572ac953..8cc8105ff9 100644 --- a/libs/binder/include/binder/IInterface.h +++ b/libs/binder/include/binder/IInterface.h @@ -230,7 +230,6 @@ constexpr const char* const kManualInterfaces[] = { "android.graphicsenv.IGpuService", "android.gui.IConsumerListener", "android.gui.IGraphicBufferConsumer", - "android.gui.ITransactionComposerListener", "android.gui.SensorEventConnection", "android.gui.SensorServer", "android.hardware.ICamera", diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index a77ca04943..a0e75ffe49 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -42,6 +42,7 @@ using namespace aidl::android::hardware::graphics; namespace android { +using gui::CallbackId; using gui::DisplayCaptureArgs; using gui::IDisplayEventConnection; using gui::IRegionSamplingListener; diff --git a/libs/gui/ITransactionCompletedListener.cpp b/libs/gui/ITransactionCompletedListener.cpp index 2b25b614e9..23d7d500c8 100644 --- a/libs/gui/ITransactionCompletedListener.cpp +++ b/libs/gui/ITransactionCompletedListener.cpp @@ -21,22 +21,11 @@ #include #include -#include #include +#include #include -namespace android { - -namespace { // Anonymous - -enum class Tag : uint32_t { - ON_TRANSACTION_COMPLETED = IBinder::FIRST_CALL_TRANSACTION, - ON_RELEASE_BUFFER, - ON_TRANSACTION_QUEUE_STALLED, - LAST = ON_TRANSACTION_QUEUE_STALLED, -}; - -} // Anonymous namespace +namespace android::gui { status_t FrameEventHistoryStats::writeToParcel(Parcel* output) const { status_t err = output->writeUint64(frameNumber); @@ -274,60 +263,6 @@ ListenerStats ListenerStats::createEmpty( return listenerStats; } -class BpTransactionCompletedListener : public SafeBpInterface { -public: - explicit BpTransactionCompletedListener(const sp& impl) - : SafeBpInterface(impl, "BpTransactionCompletedListener") { - } - - ~BpTransactionCompletedListener() override; - - void onTransactionCompleted(ListenerStats stats) override { - callRemoteAsync(Tag::ON_TRANSACTION_COMPLETED, - stats); - } - - void onReleaseBuffer(ReleaseCallbackId callbackId, sp releaseFence, - uint32_t currentMaxAcquiredBufferCount) override { - callRemoteAsync(Tag::ON_RELEASE_BUFFER, callbackId, - releaseFence, - currentMaxAcquiredBufferCount); - } - - void onTransactionQueueStalled(const String8& reason) override { - callRemoteAsync< - decltype(&ITransactionCompletedListener:: - onTransactionQueueStalled)>(Tag::ON_TRANSACTION_QUEUE_STALLED, - reason); - } -}; - -// Out-of-line virtual method definitions to trigger vtable emission in this translation unit (see -// clang warning -Wweak-vtables) -BpTransactionCompletedListener::~BpTransactionCompletedListener() = default; - -IMPLEMENT_META_INTERFACE(TransactionCompletedListener, "android.gui.ITransactionComposerListener"); - -status_t BnTransactionCompletedListener::onTransact(uint32_t code, const Parcel& data, - Parcel* reply, uint32_t flags) { - if (code < IBinder::FIRST_CALL_TRANSACTION || code > static_cast(Tag::LAST)) { - return BBinder::onTransact(code, data, reply, flags); - } - auto tag = static_cast(code); - switch (tag) { - case Tag::ON_TRANSACTION_COMPLETED: - return callLocalAsync(data, reply, - &ITransactionCompletedListener::onTransactionCompleted); - case Tag::ON_RELEASE_BUFFER: - return callLocalAsync(data, reply, &ITransactionCompletedListener::onReleaseBuffer); - case Tag::ON_TRANSACTION_QUEUE_STALLED: - return callLocalAsync(data, reply, - &ITransactionCompletedListener::onTransactionQueueStalled); - } -} - ListenerCallbacks ListenerCallbacks::filter(CallbackId::Type type) const { std::vector filteredCallbackIds; for (const auto& callbackId : callbackIds) { @@ -366,4 +301,4 @@ status_t ReleaseCallbackId::readFromParcel(const Parcel* input) { const ReleaseCallbackId ReleaseCallbackId::INVALID_ID = ReleaseCallbackId(0, 0); -}; // namespace android +}; // namespace android::gui diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 59b62fe58c..0d1a69b898 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -51,6 +51,7 @@ namespace android { +using gui::CallbackId; using gui::FocusRequest; using gui::WindowInfoHandle; diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 7085e8a349..d741c99d01 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -314,7 +314,8 @@ void TransactionCompletedListener::addSurfaceControlToCallbacks( } } -void TransactionCompletedListener::onTransactionCompleted(ListenerStats listenerStats) { +binder::Status TransactionCompletedListener::onTransactionCompleted( + const ListenerStats& listenerStats) { std::unordered_map callbacksMap; std::multimap> jankListenersMap; { @@ -454,9 +455,10 @@ void TransactionCompletedListener::onTransactionCompleted(ListenerStats listener } } } + return binder::Status::ok(); } -void TransactionCompletedListener::onTransactionQueueStalled(const String8& reason) { +binder::Status TransactionCompletedListener::onTransactionQueueStalled(const std::string& reason) { std::unordered_map> callbackCopy; { std::scoped_lock lock(mMutex); @@ -465,6 +467,7 @@ void TransactionCompletedListener::onTransactionQueueStalled(const String8& reas for (auto const& it : callbackCopy) { it.second(reason.c_str()); } + return binder::Status::ok(); } void TransactionCompletedListener::addQueueStallListener( @@ -478,9 +481,12 @@ void TransactionCompletedListener::removeQueueStallListener(void* id) { mQueueStallListeners.erase(id); } -void TransactionCompletedListener::onReleaseBuffer(ReleaseCallbackId callbackId, - sp releaseFence, - uint32_t currentMaxAcquiredBufferCount) { +binder::Status TransactionCompletedListener::onReleaseBuffer( + const ReleaseCallbackId& callbackId, + const std::optional& releaseFenceFd, + int32_t currentMaxAcquiredBufferCount) { + sp releaseFence(releaseFenceFd ? new Fence(::dup(releaseFenceFd->get())) + : Fence::NO_FENCE); ReleaseBufferCallback callback; { std::scoped_lock lock(mMutex); @@ -489,13 +495,14 @@ void TransactionCompletedListener::onReleaseBuffer(ReleaseCallbackId callbackId, if (!callback) { ALOGE("Could not call release buffer callback, buffer not found %s", callbackId.to_string().c_str()); - return; + return binder::Status::fromExceptionCode(binder::Status::EX_ILLEGAL_ARGUMENT); } std::optional optionalMaxAcquiredBufferCount = - currentMaxAcquiredBufferCount == UINT_MAX + static_cast(currentMaxAcquiredBufferCount) == UINT_MAX ? std::nullopt : std::make_optional(currentMaxAcquiredBufferCount); callback(callbackId, releaseFence, optionalMaxAcquiredBufferCount); + return binder::Status::ok(); } ReleaseBufferCallback TransactionCompletedListener::popReleaseBufferCallbackLocked( @@ -825,7 +832,11 @@ void SurfaceComposerClient::Transaction::releaseBufferIfOverwriting(const layer_ ->mReleaseCallbackThread .addReleaseCallback(state.bufferData->generateReleaseCallbackId(), fence); } else { - listener->onReleaseBuffer(state.bufferData->generateReleaseCallbackId(), fence, UINT_MAX); + std::optional fenceFd; + if (fence != Fence::NO_FENCE) { + fenceFd = os::ParcelFileDescriptor(base::unique_fd(::dup(fence->get()))); + } + listener->onReleaseBuffer(state.bufferData->generateReleaseCallbackId(), fenceFd, UINT_MAX); } } @@ -2846,7 +2857,11 @@ void ReleaseCallbackThread::threadMain() { while (!callbackInfos.empty()) { auto [callbackId, releaseFence] = callbackInfos.front(); - listener->onReleaseBuffer(callbackId, std::move(releaseFence), UINT_MAX); + std::optional fenceFd; + if (releaseFence != Fence::NO_FENCE) { + fenceFd = os::ParcelFileDescriptor(base::unique_fd(::dup(releaseFence->get()))); + } + listener->onReleaseBuffer(callbackId, fenceFd, UINT_MAX); callbackInfos.pop(); } diff --git a/libs/gui/aidl/android/gui/ITransactionCompletedListener.aidl b/libs/gui/aidl/android/gui/ITransactionCompletedListener.aidl new file mode 100644 index 0000000000..dde4d38cba --- /dev/null +++ b/libs/gui/aidl/android/gui/ITransactionCompletedListener.aidl @@ -0,0 +1,31 @@ +/* + * Copyright 2022 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.ListenerStats; +import android.gui.ReleaseCallbackId; + +/** @hide */ +oneway interface ITransactionCompletedListener { + void onTransactionCompleted(in ListenerStats stats); + + void onReleaseBuffer(in ReleaseCallbackId callbackId, + in @nullable ParcelFileDescriptor releaseFenceFd, + int currentMaxAcquiredBufferCount); + + void onTransactionQueueStalled(@utf8InCpp String name); +} diff --git a/libs/gui/aidl/android/gui/ListenerStats.aidl b/libs/gui/aidl/android/gui/ListenerStats.aidl new file mode 100644 index 0000000000..63248b2bf3 --- /dev/null +++ b/libs/gui/aidl/android/gui/ListenerStats.aidl @@ -0,0 +1,19 @@ +/* + * Copyright 2022 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; + +parcelable ListenerStats cpp_header "gui/ListenerStats.h"; diff --git a/libs/gui/aidl/android/gui/ReleaseCallbackId.aidl b/libs/gui/aidl/android/gui/ReleaseCallbackId.aidl new file mode 100644 index 0000000000..c86de34de9 --- /dev/null +++ b/libs/gui/aidl/android/gui/ReleaseCallbackId.aidl @@ -0,0 +1,19 @@ +/* + * Copyright 2022 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; + +parcelable ReleaseCallbackId cpp_header "gui/ReleaseCallbackId.h"; diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index d517e99fda..d70a7f0f1b 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -23,11 +23,11 @@ #include #include #include +#include #include #include #include #include -#include #include #include #include @@ -66,6 +66,7 @@ using gui::FrameTimelineInfo; using gui::IDisplayEventConnection; using gui::IRegionSamplingListener; using gui::IScreenCaptureListener; +using gui::ListenerCallbacks; using gui::SpHash; namespace gui { diff --git a/libs/gui/include/gui/ITransactionCompletedListener.h b/libs/gui/include/gui/ITransactionCompletedListener.h deleted file mode 100644 index 453e8f3ef5..0000000000 --- a/libs/gui/include/gui/ITransactionCompletedListener.h +++ /dev/null @@ -1,271 +0,0 @@ -/* - * Copyright 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "JankInfo.h" - -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include - -namespace android { - -class ITransactionCompletedListener; -class ListenerCallbacks; - -class CallbackId : public Parcelable { -public: - int64_t id; - enum class Type : int32_t { ON_COMPLETE, ON_COMMIT } type; - - CallbackId() {} - CallbackId(int64_t id, Type type) : id(id), type(type) {} - status_t writeToParcel(Parcel* output) const override; - status_t readFromParcel(const Parcel* input) override; - - bool operator==(const CallbackId& rhs) const { return id == rhs.id && type == rhs.type; } -}; - -struct CallbackIdHash { - std::size_t operator()(const CallbackId& key) const { return std::hash()(key.id); } -}; - -class ReleaseCallbackId : public Parcelable { -public: - static const ReleaseCallbackId INVALID_ID; - - uint64_t bufferId; - uint64_t framenumber; - ReleaseCallbackId() {} - ReleaseCallbackId(uint64_t bufferId, uint64_t framenumber) - : bufferId(bufferId), framenumber(framenumber) {} - status_t writeToParcel(Parcel* output) const override; - status_t readFromParcel(const Parcel* input) override; - - bool operator==(const ReleaseCallbackId& rhs) const { - return bufferId == rhs.bufferId && framenumber == rhs.framenumber; - } - bool operator!=(const ReleaseCallbackId& rhs) const { return !operator==(rhs); } - std::string to_string() const { - if (*this == INVALID_ID) return "INVALID_ID"; - - return "bufferId:" + std::to_string(bufferId) + - " framenumber:" + std::to_string(framenumber); - } -}; - -struct ReleaseBufferCallbackIdHash { - std::size_t operator()(const ReleaseCallbackId& key) const { - return std::hash()(key.bufferId); - } -}; - -class FrameEventHistoryStats : public Parcelable { -public: - status_t writeToParcel(Parcel* output) const override; - status_t readFromParcel(const Parcel* input) override; - - FrameEventHistoryStats() = default; - FrameEventHistoryStats(uint64_t fn, const sp& gpuCompFence, CompositorTiming compTiming, - nsecs_t refreshTime, nsecs_t dequeueReadyTime) - : frameNumber(fn), - gpuCompositionDoneFence(gpuCompFence), - compositorTiming(compTiming), - refreshStartTime(refreshTime), - dequeueReadyTime(dequeueReadyTime) {} - - uint64_t frameNumber; - sp gpuCompositionDoneFence; - CompositorTiming compositorTiming; - nsecs_t refreshStartTime; - nsecs_t dequeueReadyTime; -}; - -/** - * Jank information representing SurfaceFlinger's jank classification about frames for a specific - * surface. - */ -class JankData : public Parcelable { -public: - status_t writeToParcel(Parcel* output) const override; - status_t readFromParcel(const Parcel* input) override; - - JankData(); - JankData(int64_t frameVsyncId, int32_t jankType) - : frameVsyncId(frameVsyncId), jankType(jankType) {} - - // Identifier for the frame submitted with Transaction.setFrameTimelineVsyncId - int64_t frameVsyncId; - - // Bitmask of janks that occurred - int32_t jankType; -}; - -class SurfaceStats : public Parcelable { -public: - status_t writeToParcel(Parcel* output) const override; - status_t readFromParcel(const Parcel* input) override; - - SurfaceStats() = default; - SurfaceStats(const sp& sc, std::variant> acquireTimeOrFence, - const sp& prevReleaseFence, std::optional hint, - uint32_t currentMaxAcquiredBuffersCount, FrameEventHistoryStats frameEventStats, - std::vector jankData, ReleaseCallbackId previousReleaseCallbackId) - : surfaceControl(sc), - acquireTimeOrFence(std::move(acquireTimeOrFence)), - previousReleaseFence(prevReleaseFence), - transformHint(hint), - currentMaxAcquiredBufferCount(currentMaxAcquiredBuffersCount), - eventStats(frameEventStats), - jankData(std::move(jankData)), - previousReleaseCallbackId(previousReleaseCallbackId) {} - - sp surfaceControl; - std::variant> acquireTimeOrFence = -1; - sp previousReleaseFence; - std::optional transformHint = 0; - uint32_t currentMaxAcquiredBufferCount = 0; - FrameEventHistoryStats eventStats; - std::vector jankData; - ReleaseCallbackId previousReleaseCallbackId; -}; - -class TransactionStats : public Parcelable { -public: - status_t writeToParcel(Parcel* output) const override; - status_t readFromParcel(const Parcel* input) override; - - TransactionStats() = default; - TransactionStats(const std::vector& ids) : callbackIds(ids) {} - TransactionStats(const std::unordered_set& ids) - : callbackIds(ids.begin(), ids.end()) {} - TransactionStats(const std::vector& ids, nsecs_t latch, const sp& present, - const std::vector& surfaces) - : callbackIds(ids), latchTime(latch), presentFence(present), surfaceStats(surfaces) {} - - std::vector callbackIds; - nsecs_t latchTime = -1; - sp presentFence = nullptr; - std::vector surfaceStats; -}; - -class ListenerStats : public Parcelable { -public: - status_t writeToParcel(Parcel* output) const override; - status_t readFromParcel(const Parcel* input) override; - - static ListenerStats createEmpty( - const sp& listener, - const std::unordered_set& callbackIds); - - sp listener; - std::vector transactionStats; -}; - -class ITransactionCompletedListener : public IInterface { -public: - DECLARE_META_INTERFACE(TransactionCompletedListener) - - virtual void onTransactionCompleted(ListenerStats stats) = 0; - - virtual void onReleaseBuffer(ReleaseCallbackId callbackId, sp releaseFence, - uint32_t currentMaxAcquiredBufferCount) = 0; - - virtual void onTransactionQueueStalled(const String8& name) = 0; -}; - -class BnTransactionCompletedListener : public SafeBnInterface { -public: - BnTransactionCompletedListener() - : SafeBnInterface("BnTransactionCompletedListener") {} - - status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, - uint32_t flags = 0) override; -}; - -class ListenerCallbacks { -public: - ListenerCallbacks(const sp& listener, - const std::unordered_set& callbacks) - : transactionCompletedListener(listener), - callbackIds(callbacks.begin(), callbacks.end()) {} - - ListenerCallbacks(const sp& listener, const std::vector& ids) - : transactionCompletedListener(listener), callbackIds(ids) {} - - bool operator==(const ListenerCallbacks& rhs) const { - if (transactionCompletedListener != rhs.transactionCompletedListener) { - return false; - } - if (callbackIds.empty()) { - return rhs.callbackIds.empty(); - } - return callbackIds.front().id == rhs.callbackIds.front().id; - } - - // Returns a new ListenerCallbacks filtered by type - ListenerCallbacks filter(CallbackId::Type type) const; - - sp transactionCompletedListener; - std::vector callbackIds; -}; - -struct IListenerHash { - std::size_t operator()(const sp& strongPointer) const { - return std::hash{}(strongPointer.get()); - } -}; - -struct CallbackIdsHash { - // CallbackId vectors have several properties that let us get away with this simple hash. - // 1) CallbackIds are never 0 so if something has gone wrong and our CallbackId vector is - // empty we can still hash 0. - // 2) CallbackId vectors for the same listener either are identical or contain none of the - // same members. It is sufficient to just check the first CallbackId in the vectors. If - // they match, they are the same. If they do not match, they are not the same. - std::size_t operator()(const std::vector& callbackIds) const { - return std::hash{}((callbackIds.empty()) ? 0 : callbackIds.front().id); - } -}; - -struct ListenerCallbacksHash { - std::size_t HashCombine(size_t value1, size_t value2) const { - return value1 ^ (value2 + 0x9e3779b9 + (value1 << 6) + (value1 >> 2)); - } - - std::size_t operator()(const ListenerCallbacks& listenerCallbacks) const { - struct IListenerHash listenerHasher; - struct CallbackIdsHash callbackIdsHasher; - - std::size_t listenerHash = listenerHasher(listenerCallbacks.transactionCompletedListener); - std::size_t callbackIdsHash = callbackIdsHasher(listenerCallbacks.callbackIds); - - return HashCombine(listenerHash, callbackIdsHash); - } -}; - -} // namespace android diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index 45a84f6c66..c5fdf82d4f 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -21,10 +21,10 @@ #include #include +#include #include #include #include -#include #include #include @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -56,6 +57,9 @@ class Parcel; using gui::ISurfaceComposerClient; using gui::LayerMetadata; +using gui::ITransactionCompletedListener; +using gui::ReleaseCallbackId; + struct client_cache_t { wp token = nullptr; uint64_t id; diff --git a/libs/gui/include/gui/ListenerStats.h b/libs/gui/include/gui/ListenerStats.h new file mode 100644 index 0000000000..3a12802146 --- /dev/null +++ b/libs/gui/include/gui/ListenerStats.h @@ -0,0 +1,225 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "JankInfo.h" + +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include + +namespace android::gui { + +class CallbackId : public Parcelable { +public: + int64_t id; + enum class Type : int32_t { ON_COMPLETE, ON_COMMIT } type; + + CallbackId() {} + CallbackId(int64_t id, Type type) : id(id), type(type) {} + status_t writeToParcel(Parcel* output) const override; + status_t readFromParcel(const Parcel* input) override; + + bool operator==(const CallbackId& rhs) const { return id == rhs.id && type == rhs.type; } +}; + +struct CallbackIdHash { + std::size_t operator()(const CallbackId& key) const { return std::hash()(key.id); } +}; + +struct ReleaseBufferCallbackIdHash { + std::size_t operator()(const ReleaseCallbackId& key) const { + return std::hash()(key.bufferId); + } +}; + +class FrameEventHistoryStats : public Parcelable { +public: + status_t writeToParcel(Parcel* output) const override; + status_t readFromParcel(const Parcel* input) override; + + FrameEventHistoryStats() = default; + FrameEventHistoryStats(uint64_t fn, const sp& gpuCompFence, CompositorTiming compTiming, + nsecs_t refreshTime, nsecs_t dequeueReadyTime) + : frameNumber(fn), + gpuCompositionDoneFence(gpuCompFence), + compositorTiming(compTiming), + refreshStartTime(refreshTime), + dequeueReadyTime(dequeueReadyTime) {} + + uint64_t frameNumber; + sp gpuCompositionDoneFence; + CompositorTiming compositorTiming; + nsecs_t refreshStartTime; + nsecs_t dequeueReadyTime; +}; + +/** + * Jank information representing SurfaceFlinger's jank classification about frames for a specific + * surface. + */ +class JankData : public Parcelable { +public: + status_t writeToParcel(Parcel* output) const override; + status_t readFromParcel(const Parcel* input) override; + + JankData(); + JankData(int64_t frameVsyncId, int32_t jankType) + : frameVsyncId(frameVsyncId), jankType(jankType) {} + + // Identifier for the frame submitted with Transaction.setFrameTimelineVsyncId + int64_t frameVsyncId; + + // Bitmask of janks that occurred + int32_t jankType; +}; + +class SurfaceStats : public Parcelable { +public: + status_t writeToParcel(Parcel* output) const override; + status_t readFromParcel(const Parcel* input) override; + + SurfaceStats() = default; + SurfaceStats(const sp& sc, std::variant> acquireTimeOrFence, + const sp& prevReleaseFence, std::optional hint, + uint32_t currentMaxAcquiredBuffersCount, FrameEventHistoryStats frameEventStats, + std::vector jankData, ReleaseCallbackId previousReleaseCallbackId) + : surfaceControl(sc), + acquireTimeOrFence(std::move(acquireTimeOrFence)), + previousReleaseFence(prevReleaseFence), + transformHint(hint), + currentMaxAcquiredBufferCount(currentMaxAcquiredBuffersCount), + eventStats(frameEventStats), + jankData(std::move(jankData)), + previousReleaseCallbackId(previousReleaseCallbackId) {} + + sp surfaceControl; + std::variant> acquireTimeOrFence = -1; + sp previousReleaseFence; + std::optional transformHint = 0; + uint32_t currentMaxAcquiredBufferCount = 0; + FrameEventHistoryStats eventStats; + std::vector jankData; + ReleaseCallbackId previousReleaseCallbackId; +}; + +class TransactionStats : public Parcelable { +public: + status_t writeToParcel(Parcel* output) const override; + status_t readFromParcel(const Parcel* input) override; + + TransactionStats() = default; + TransactionStats(const std::vector& ids) : callbackIds(ids) {} + TransactionStats(const std::unordered_set& ids) + : callbackIds(ids.begin(), ids.end()) {} + TransactionStats(const std::vector& ids, nsecs_t latch, const sp& present, + const std::vector& surfaces) + : callbackIds(ids), latchTime(latch), presentFence(present), surfaceStats(surfaces) {} + + std::vector callbackIds; + nsecs_t latchTime = -1; + sp presentFence = nullptr; + std::vector surfaceStats; +}; + +class ListenerStats : public Parcelable { +public: + status_t writeToParcel(Parcel* output) const override; + status_t readFromParcel(const Parcel* input) override; + + static ListenerStats createEmpty( + const sp& listener, + const std::unordered_set& callbackIds); + + sp listener; + std::vector transactionStats; +}; + +class ListenerCallbacks { +public: + ListenerCallbacks(const sp& listener, + const std::unordered_set& callbacks) + : transactionCompletedListener(listener), + callbackIds(callbacks.begin(), callbacks.end()) {} + + ListenerCallbacks(const sp& listener, const std::vector& ids) + : transactionCompletedListener(listener), callbackIds(ids) {} + + bool operator==(const ListenerCallbacks& rhs) const { + if (transactionCompletedListener != rhs.transactionCompletedListener) { + return false; + } + if (callbackIds.empty()) { + return rhs.callbackIds.empty(); + } + return callbackIds.front().id == rhs.callbackIds.front().id; + } + + // Returns a new ListenerCallbacks filtered by type + ListenerCallbacks filter(CallbackId::Type type) const; + + sp transactionCompletedListener; + std::vector callbackIds; +}; + +struct IListenerHash { + std::size_t operator()(const sp& strongPointer) const { + return std::hash{}(strongPointer.get()); + } +}; + +struct CallbackIdsHash { + // CallbackId vectors have several properties that let us get away with this simple hash. + // 1) CallbackIds are never 0 so if something has gone wrong and our CallbackId vector is + // empty we can still hash 0. + // 2) CallbackId vectors for the same listener either are identical or contain none of the + // same members. It is sufficient to just check the first CallbackId in the vectors. If + // they match, they are the same. If they do not match, they are not the same. + std::size_t operator()(const std::vector& callbackIds) const { + return std::hash{}((callbackIds.empty()) ? 0 : callbackIds.front().id); + } +}; + +struct ListenerCallbacksHash { + std::size_t HashCombine(size_t value1, size_t value2) const { + return value1 ^ (value2 + 0x9e3779b9 + (value1 << 6) + (value1 >> 2)); + } + + std::size_t operator()(const ListenerCallbacks& listenerCallbacks) const { + struct IListenerHash listenerHasher; + struct CallbackIdsHash callbackIdsHasher; + + std::size_t listenerHash = listenerHasher(listenerCallbacks.transactionCompletedListener); + std::size_t callbackIdsHash = callbackIdsHasher(listenerCallbacks.callbackIds); + + return HashCombine(listenerHash, callbackIdsHash); + } +}; + +} // namespace android::gui diff --git a/libs/gui/include/gui/ReleaseCallbackId.h b/libs/gui/include/gui/ReleaseCallbackId.h new file mode 100644 index 0000000000..142ee5a727 --- /dev/null +++ b/libs/gui/include/gui/ReleaseCallbackId.h @@ -0,0 +1,50 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#include + +namespace android::gui { + +class ReleaseCallbackId : public Parcelable { +public: + static const ReleaseCallbackId INVALID_ID; + + uint64_t bufferId; + uint64_t framenumber; + ReleaseCallbackId() {} + ReleaseCallbackId(uint64_t bufferId, uint64_t framenumber) + : bufferId(bufferId), framenumber(framenumber) {} + status_t writeToParcel(Parcel* output) const override; + status_t readFromParcel(const Parcel* input) override; + + bool operator==(const ReleaseCallbackId& rhs) const { + return bufferId == rhs.bufferId && framenumber == rhs.framenumber; + } + bool operator!=(const ReleaseCallbackId& rhs) const { return !operator==(rhs); } + std::string to_string() const { + if (*this == INVALID_ID) return "INVALID_ID"; + + return "bufferId:" + std::to_string(bufferId) + + " framenumber:" + std::to_string(framenumber); + } +}; + +} // namespace android::gui diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index df47002b3b..96d3a23bec 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -42,10 +42,13 @@ #include +#include + #include #include -#include #include +#include +#include #include #include #include @@ -59,11 +62,21 @@ class IGraphicBufferProducer; class ITunnelModeEnabledListener; class Region; +using gui::BnTransactionCompletedListener; +using gui::CallbackId; +using gui::CallbackIdHash; using gui::DisplayCaptureArgs; +using gui::FrameEventHistoryStats; using gui::IRegionSamplingListener; using gui::ISurfaceComposerClient; +using gui::ITransactionCompletedListener; +using gui::JankData; using gui::LayerCaptureArgs; using gui::LayerMetadata; +using gui::ListenerStats; +using gui::ReleaseBufferCallbackIdHash; +using gui::ReleaseCallbackId; +using gui::SurfaceStats; struct SurfaceControlStats { SurfaceControlStats(const sp& sc, nsecs_t latchTime, @@ -825,17 +838,17 @@ public: void setReleaseBufferCallback(const ReleaseCallbackId&, ReleaseBufferCallback); // BnTransactionCompletedListener overrides - void onTransactionCompleted(ListenerStats stats) override; - void onReleaseBuffer(ReleaseCallbackId, sp releaseFence, - uint32_t currentMaxAcquiredBufferCount) override; + binder::Status onTransactionCompleted(const ListenerStats& stats) override; + binder::Status onReleaseBuffer(const ReleaseCallbackId& callbackId, + const std::optional& releaseFenceFd, + int32_t currentMaxAcquiredBufferCount) override; + binder::Status onTransactionQueueStalled(const std::string& reason) override; void removeReleaseBufferCallback(const ReleaseCallbackId& callbackId); // For Testing Only static void setInstance(const sp&); - void onTransactionQueueStalled(const String8& reason) override; - private: ReleaseBufferCallback popReleaseBufferCallbackLocked(const ReleaseCallbackId&); static sp sInstance; diff --git a/services/surfaceflinger/FrontEnd/TransactionHandler.cpp b/services/surfaceflinger/FrontEnd/TransactionHandler.cpp index 8629671214..c2109b3aa5 100644 --- a/services/surfaceflinger/FrontEnd/TransactionHandler.cpp +++ b/services/surfaceflinger/FrontEnd/TransactionHandler.cpp @@ -177,7 +177,7 @@ void TransactionHandler::onTransactionQueueStalled(uint64_t transactionId, } mStalledTransactions.push_back(transactionId); - listener->onTransactionQueueStalled(String8(reason.c_str())); + listener->onTransactionQueueStalled(reason); } void TransactionHandler::removeFromStalledTransactions(uint64_t id) { diff --git a/services/surfaceflinger/FrontEnd/TransactionHandler.h b/services/surfaceflinger/FrontEnd/TransactionHandler.h index a06b870549..475ff1b1dc 100644 --- a/services/surfaceflinger/FrontEnd/TransactionHandler.h +++ b/services/surfaceflinger/FrontEnd/TransactionHandler.h @@ -29,6 +29,7 @@ namespace android { class TestableSurfaceFlinger; +using gui::IListenerHash; namespace surfaceflinger::frontend { class TransactionHandler { diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 0017af0476..56abc516fd 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -2604,9 +2604,12 @@ void Layer::callReleaseBufferCallback(const sp& l return; } ATRACE_FORMAT_INSTANT("callReleaseBufferCallback %s - %" PRIu64, getDebugName(), framenumber); - listener->onReleaseBuffer({buffer->getId(), framenumber}, - releaseFence ? releaseFence : Fence::NO_FENCE, - currentMaxAcquiredBufferCount); + std::optional fenceFd; + if (releaseFence) { + fenceFd = os::ParcelFileDescriptor(base::unique_fd(::dup(releaseFence->get()))); + } + listener->onReleaseBuffer({buffer->getId(), framenumber}, fenceFd, + static_cast(currentMaxAcquiredBufferCount)); } void Layer::onLayerDisplayed(ftl::SharedFuture futureFenceResult) { diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index d4c4fb28f5..55644e2a41 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -7113,8 +7113,7 @@ std::shared_ptr SurfaceFlinger::getExternalTextur layerName, static_cast(mMaxRenderTargetSize)); ALOGD("%s", errorMessage.c_str()); if (bufferData.releaseBufferListener) { - bufferData.releaseBufferListener->onTransactionQueueStalled( - String8(errorMessage.c_str())); + bufferData.releaseBufferListener->onTransactionQueueStalled(errorMessage); } return nullptr; } @@ -7132,7 +7131,7 @@ std::shared_ptr SurfaceFlinger::getExternalTextur if (bufferData.releaseBufferListener) { bufferData.releaseBufferListener->onTransactionQueueStalled( - String8("Buffer processing hung due to full buffer cache")); + "Buffer processing hung due to full buffer cache"); } } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 3354b24bbb..8fa427843b 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -34,8 +35,8 @@ #include #include #include -#include #include + #include #include #include @@ -125,7 +126,9 @@ using frontend::TransactionHandler; using gui::CaptureArgs; using gui::DisplayCaptureArgs; using gui::IRegionSamplingListener; +using gui::ITransactionCompletedListener; using gui::LayerCaptureArgs; + using gui::ScreenCaptureResults; namespace frametimeline { diff --git a/services/surfaceflinger/TransactionCallbackInvoker.h b/services/surfaceflinger/TransactionCallbackInvoker.h index 61ff9bce98..c09bcce067 100644 --- a/services/surfaceflinger/TransactionCallbackInvoker.h +++ b/services/surfaceflinger/TransactionCallbackInvoker.h @@ -26,14 +26,27 @@ #include #include +#include + #include -#include -#include +#include +#include +#include #include #include namespace android { +using gui::CallbackId; +using gui::FrameEventHistoryStats; +using gui::IListenerHash; +using gui::ITransactionCompletedListener; +using gui::JankData; +using gui::ListenerCallbacks; +using gui::ListenerStats; +using gui::ReleaseCallbackId; +using gui::TransactionStats; + class CallbackHandle : public RefBase { public: CallbackHandle(const sp& transactionListener, const std::vector& ids, -- cgit v1.2.3-59-g8ed1b From ffee3bc5ba2b696721a86b615c1f0ef5ee2afa55 Mon Sep 17 00:00:00 2001 From: Huihong Luo Date: Tue, 17 Jan 2023 16:14:35 +0000 Subject: Revert "Migrate ITransactionCompletedListener to AIDL" This reverts commit c50b4988e93872bfe023a4e099548f84bdfd998d. Reason for revert: CTS failures, b/262211898 Change-Id: Iaff863f8af98c11dbf852cccad50e55148d87cee --- libs/binder/include/binder/IInterface.h | 1 + libs/gui/ISurfaceComposer.cpp | 1 - libs/gui/ITransactionCompletedListener.cpp | 71 +++++- libs/gui/LayerState.cpp | 1 - libs/gui/SurfaceComposerClient.cpp | 33 +-- .../android/gui/ITransactionCompletedListener.aidl | 31 --- libs/gui/aidl/android/gui/ListenerStats.aidl | 19 -- libs/gui/aidl/android/gui/ReleaseCallbackId.aidl | 19 -- libs/gui/include/gui/ISurfaceComposer.h | 3 +- .../include/gui/ITransactionCompletedListener.h | 271 +++++++++++++++++++++ libs/gui/include/gui/LayerState.h | 6 +- libs/gui/include/gui/ListenerStats.h | 225 ----------------- libs/gui/include/gui/ReleaseCallbackId.h | 50 ---- libs/gui/include/gui/SurfaceComposerClient.h | 25 +- .../surfaceflinger/FrontEnd/TransactionHandler.cpp | 2 +- .../surfaceflinger/FrontEnd/TransactionHandler.h | 1 - services/surfaceflinger/Layer.cpp | 9 +- services/surfaceflinger/SurfaceFlinger.cpp | 5 +- services/surfaceflinger/SurfaceFlinger.h | 5 +- .../surfaceflinger/TransactionCallbackInvoker.h | 17 +- 20 files changed, 367 insertions(+), 428 deletions(-) delete mode 100644 libs/gui/aidl/android/gui/ITransactionCompletedListener.aidl delete mode 100644 libs/gui/aidl/android/gui/ListenerStats.aidl delete mode 100644 libs/gui/aidl/android/gui/ReleaseCallbackId.aidl create mode 100644 libs/gui/include/gui/ITransactionCompletedListener.h delete mode 100644 libs/gui/include/gui/ListenerStats.h delete mode 100644 libs/gui/include/gui/ReleaseCallbackId.h (limited to 'libs/gui/LayerState.cpp') diff --git a/libs/binder/include/binder/IInterface.h b/libs/binder/include/binder/IInterface.h index 8cc8105ff9..dc572ac953 100644 --- a/libs/binder/include/binder/IInterface.h +++ b/libs/binder/include/binder/IInterface.h @@ -230,6 +230,7 @@ constexpr const char* const kManualInterfaces[] = { "android.graphicsenv.IGpuService", "android.gui.IConsumerListener", "android.gui.IGraphicBufferConsumer", + "android.gui.ITransactionComposerListener", "android.gui.SensorEventConnection", "android.gui.SensorServer", "android.hardware.ICamera", diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index a0e75ffe49..a77ca04943 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -42,7 +42,6 @@ using namespace aidl::android::hardware::graphics; namespace android { -using gui::CallbackId; using gui::DisplayCaptureArgs; using gui::IDisplayEventConnection; using gui::IRegionSamplingListener; diff --git a/libs/gui/ITransactionCompletedListener.cpp b/libs/gui/ITransactionCompletedListener.cpp index 23d7d500c8..2b25b614e9 100644 --- a/libs/gui/ITransactionCompletedListener.cpp +++ b/libs/gui/ITransactionCompletedListener.cpp @@ -21,11 +21,22 @@ #include #include +#include #include -#include #include -namespace android::gui { +namespace android { + +namespace { // Anonymous + +enum class Tag : uint32_t { + ON_TRANSACTION_COMPLETED = IBinder::FIRST_CALL_TRANSACTION, + ON_RELEASE_BUFFER, + ON_TRANSACTION_QUEUE_STALLED, + LAST = ON_TRANSACTION_QUEUE_STALLED, +}; + +} // Anonymous namespace status_t FrameEventHistoryStats::writeToParcel(Parcel* output) const { status_t err = output->writeUint64(frameNumber); @@ -263,6 +274,60 @@ ListenerStats ListenerStats::createEmpty( return listenerStats; } +class BpTransactionCompletedListener : public SafeBpInterface { +public: + explicit BpTransactionCompletedListener(const sp& impl) + : SafeBpInterface(impl, "BpTransactionCompletedListener") { + } + + ~BpTransactionCompletedListener() override; + + void onTransactionCompleted(ListenerStats stats) override { + callRemoteAsync(Tag::ON_TRANSACTION_COMPLETED, + stats); + } + + void onReleaseBuffer(ReleaseCallbackId callbackId, sp releaseFence, + uint32_t currentMaxAcquiredBufferCount) override { + callRemoteAsync(Tag::ON_RELEASE_BUFFER, callbackId, + releaseFence, + currentMaxAcquiredBufferCount); + } + + void onTransactionQueueStalled(const String8& reason) override { + callRemoteAsync< + decltype(&ITransactionCompletedListener:: + onTransactionQueueStalled)>(Tag::ON_TRANSACTION_QUEUE_STALLED, + reason); + } +}; + +// Out-of-line virtual method definitions to trigger vtable emission in this translation unit (see +// clang warning -Wweak-vtables) +BpTransactionCompletedListener::~BpTransactionCompletedListener() = default; + +IMPLEMENT_META_INTERFACE(TransactionCompletedListener, "android.gui.ITransactionComposerListener"); + +status_t BnTransactionCompletedListener::onTransact(uint32_t code, const Parcel& data, + Parcel* reply, uint32_t flags) { + if (code < IBinder::FIRST_CALL_TRANSACTION || code > static_cast(Tag::LAST)) { + return BBinder::onTransact(code, data, reply, flags); + } + auto tag = static_cast(code); + switch (tag) { + case Tag::ON_TRANSACTION_COMPLETED: + return callLocalAsync(data, reply, + &ITransactionCompletedListener::onTransactionCompleted); + case Tag::ON_RELEASE_BUFFER: + return callLocalAsync(data, reply, &ITransactionCompletedListener::onReleaseBuffer); + case Tag::ON_TRANSACTION_QUEUE_STALLED: + return callLocalAsync(data, reply, + &ITransactionCompletedListener::onTransactionQueueStalled); + } +} + ListenerCallbacks ListenerCallbacks::filter(CallbackId::Type type) const { std::vector filteredCallbackIds; for (const auto& callbackId : callbackIds) { @@ -301,4 +366,4 @@ status_t ReleaseCallbackId::readFromParcel(const Parcel* input) { const ReleaseCallbackId ReleaseCallbackId::INVALID_ID = ReleaseCallbackId(0, 0); -}; // namespace android::gui +}; // namespace android diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 0d1a69b898..59b62fe58c 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -51,7 +51,6 @@ namespace android { -using gui::CallbackId; using gui::FocusRequest; using gui::WindowInfoHandle; diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index d741c99d01..7085e8a349 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -314,8 +314,7 @@ void TransactionCompletedListener::addSurfaceControlToCallbacks( } } -binder::Status TransactionCompletedListener::onTransactionCompleted( - const ListenerStats& listenerStats) { +void TransactionCompletedListener::onTransactionCompleted(ListenerStats listenerStats) { std::unordered_map callbacksMap; std::multimap> jankListenersMap; { @@ -455,10 +454,9 @@ binder::Status TransactionCompletedListener::onTransactionCompleted( } } } - return binder::Status::ok(); } -binder::Status TransactionCompletedListener::onTransactionQueueStalled(const std::string& reason) { +void TransactionCompletedListener::onTransactionQueueStalled(const String8& reason) { std::unordered_map> callbackCopy; { std::scoped_lock lock(mMutex); @@ -467,7 +465,6 @@ binder::Status TransactionCompletedListener::onTransactionQueueStalled(const std for (auto const& it : callbackCopy) { it.second(reason.c_str()); } - return binder::Status::ok(); } void TransactionCompletedListener::addQueueStallListener( @@ -481,12 +478,9 @@ void TransactionCompletedListener::removeQueueStallListener(void* id) { mQueueStallListeners.erase(id); } -binder::Status TransactionCompletedListener::onReleaseBuffer( - const ReleaseCallbackId& callbackId, - const std::optional& releaseFenceFd, - int32_t currentMaxAcquiredBufferCount) { - sp releaseFence(releaseFenceFd ? new Fence(::dup(releaseFenceFd->get())) - : Fence::NO_FENCE); +void TransactionCompletedListener::onReleaseBuffer(ReleaseCallbackId callbackId, + sp releaseFence, + uint32_t currentMaxAcquiredBufferCount) { ReleaseBufferCallback callback; { std::scoped_lock lock(mMutex); @@ -495,14 +489,13 @@ binder::Status TransactionCompletedListener::onReleaseBuffer( if (!callback) { ALOGE("Could not call release buffer callback, buffer not found %s", callbackId.to_string().c_str()); - return binder::Status::fromExceptionCode(binder::Status::EX_ILLEGAL_ARGUMENT); + return; } std::optional optionalMaxAcquiredBufferCount = - static_cast(currentMaxAcquiredBufferCount) == UINT_MAX + currentMaxAcquiredBufferCount == UINT_MAX ? std::nullopt : std::make_optional(currentMaxAcquiredBufferCount); callback(callbackId, releaseFence, optionalMaxAcquiredBufferCount); - return binder::Status::ok(); } ReleaseBufferCallback TransactionCompletedListener::popReleaseBufferCallbackLocked( @@ -832,11 +825,7 @@ void SurfaceComposerClient::Transaction::releaseBufferIfOverwriting(const layer_ ->mReleaseCallbackThread .addReleaseCallback(state.bufferData->generateReleaseCallbackId(), fence); } else { - std::optional fenceFd; - if (fence != Fence::NO_FENCE) { - fenceFd = os::ParcelFileDescriptor(base::unique_fd(::dup(fence->get()))); - } - listener->onReleaseBuffer(state.bufferData->generateReleaseCallbackId(), fenceFd, UINT_MAX); + listener->onReleaseBuffer(state.bufferData->generateReleaseCallbackId(), fence, UINT_MAX); } } @@ -2857,11 +2846,7 @@ void ReleaseCallbackThread::threadMain() { while (!callbackInfos.empty()) { auto [callbackId, releaseFence] = callbackInfos.front(); - std::optional fenceFd; - if (releaseFence != Fence::NO_FENCE) { - fenceFd = os::ParcelFileDescriptor(base::unique_fd(::dup(releaseFence->get()))); - } - listener->onReleaseBuffer(callbackId, fenceFd, UINT_MAX); + listener->onReleaseBuffer(callbackId, std::move(releaseFence), UINT_MAX); callbackInfos.pop(); } diff --git a/libs/gui/aidl/android/gui/ITransactionCompletedListener.aidl b/libs/gui/aidl/android/gui/ITransactionCompletedListener.aidl deleted file mode 100644 index dde4d38cba..0000000000 --- a/libs/gui/aidl/android/gui/ITransactionCompletedListener.aidl +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2022 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.ListenerStats; -import android.gui.ReleaseCallbackId; - -/** @hide */ -oneway interface ITransactionCompletedListener { - void onTransactionCompleted(in ListenerStats stats); - - void onReleaseBuffer(in ReleaseCallbackId callbackId, - in @nullable ParcelFileDescriptor releaseFenceFd, - int currentMaxAcquiredBufferCount); - - void onTransactionQueueStalled(@utf8InCpp String name); -} diff --git a/libs/gui/aidl/android/gui/ListenerStats.aidl b/libs/gui/aidl/android/gui/ListenerStats.aidl deleted file mode 100644 index 63248b2bf3..0000000000 --- a/libs/gui/aidl/android/gui/ListenerStats.aidl +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright 2022 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; - -parcelable ListenerStats cpp_header "gui/ListenerStats.h"; diff --git a/libs/gui/aidl/android/gui/ReleaseCallbackId.aidl b/libs/gui/aidl/android/gui/ReleaseCallbackId.aidl deleted file mode 100644 index c86de34de9..0000000000 --- a/libs/gui/aidl/android/gui/ReleaseCallbackId.aidl +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright 2022 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; - -parcelable ReleaseCallbackId cpp_header "gui/ReleaseCallbackId.h"; diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index d70a7f0f1b..d517e99fda 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -23,11 +23,11 @@ #include #include #include -#include #include #include #include #include +#include #include #include #include @@ -66,7 +66,6 @@ using gui::FrameTimelineInfo; using gui::IDisplayEventConnection; using gui::IRegionSamplingListener; using gui::IScreenCaptureListener; -using gui::ListenerCallbacks; using gui::SpHash; namespace gui { diff --git a/libs/gui/include/gui/ITransactionCompletedListener.h b/libs/gui/include/gui/ITransactionCompletedListener.h new file mode 100644 index 0000000000..453e8f3ef5 --- /dev/null +++ b/libs/gui/include/gui/ITransactionCompletedListener.h @@ -0,0 +1,271 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "JankInfo.h" + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +namespace android { + +class ITransactionCompletedListener; +class ListenerCallbacks; + +class CallbackId : public Parcelable { +public: + int64_t id; + enum class Type : int32_t { ON_COMPLETE, ON_COMMIT } type; + + CallbackId() {} + CallbackId(int64_t id, Type type) : id(id), type(type) {} + status_t writeToParcel(Parcel* output) const override; + status_t readFromParcel(const Parcel* input) override; + + bool operator==(const CallbackId& rhs) const { return id == rhs.id && type == rhs.type; } +}; + +struct CallbackIdHash { + std::size_t operator()(const CallbackId& key) const { return std::hash()(key.id); } +}; + +class ReleaseCallbackId : public Parcelable { +public: + static const ReleaseCallbackId INVALID_ID; + + uint64_t bufferId; + uint64_t framenumber; + ReleaseCallbackId() {} + ReleaseCallbackId(uint64_t bufferId, uint64_t framenumber) + : bufferId(bufferId), framenumber(framenumber) {} + status_t writeToParcel(Parcel* output) const override; + status_t readFromParcel(const Parcel* input) override; + + bool operator==(const ReleaseCallbackId& rhs) const { + return bufferId == rhs.bufferId && framenumber == rhs.framenumber; + } + bool operator!=(const ReleaseCallbackId& rhs) const { return !operator==(rhs); } + std::string to_string() const { + if (*this == INVALID_ID) return "INVALID_ID"; + + return "bufferId:" + std::to_string(bufferId) + + " framenumber:" + std::to_string(framenumber); + } +}; + +struct ReleaseBufferCallbackIdHash { + std::size_t operator()(const ReleaseCallbackId& key) const { + return std::hash()(key.bufferId); + } +}; + +class FrameEventHistoryStats : public Parcelable { +public: + status_t writeToParcel(Parcel* output) const override; + status_t readFromParcel(const Parcel* input) override; + + FrameEventHistoryStats() = default; + FrameEventHistoryStats(uint64_t fn, const sp& gpuCompFence, CompositorTiming compTiming, + nsecs_t refreshTime, nsecs_t dequeueReadyTime) + : frameNumber(fn), + gpuCompositionDoneFence(gpuCompFence), + compositorTiming(compTiming), + refreshStartTime(refreshTime), + dequeueReadyTime(dequeueReadyTime) {} + + uint64_t frameNumber; + sp gpuCompositionDoneFence; + CompositorTiming compositorTiming; + nsecs_t refreshStartTime; + nsecs_t dequeueReadyTime; +}; + +/** + * Jank information representing SurfaceFlinger's jank classification about frames for a specific + * surface. + */ +class JankData : public Parcelable { +public: + status_t writeToParcel(Parcel* output) const override; + status_t readFromParcel(const Parcel* input) override; + + JankData(); + JankData(int64_t frameVsyncId, int32_t jankType) + : frameVsyncId(frameVsyncId), jankType(jankType) {} + + // Identifier for the frame submitted with Transaction.setFrameTimelineVsyncId + int64_t frameVsyncId; + + // Bitmask of janks that occurred + int32_t jankType; +}; + +class SurfaceStats : public Parcelable { +public: + status_t writeToParcel(Parcel* output) const override; + status_t readFromParcel(const Parcel* input) override; + + SurfaceStats() = default; + SurfaceStats(const sp& sc, std::variant> acquireTimeOrFence, + const sp& prevReleaseFence, std::optional hint, + uint32_t currentMaxAcquiredBuffersCount, FrameEventHistoryStats frameEventStats, + std::vector jankData, ReleaseCallbackId previousReleaseCallbackId) + : surfaceControl(sc), + acquireTimeOrFence(std::move(acquireTimeOrFence)), + previousReleaseFence(prevReleaseFence), + transformHint(hint), + currentMaxAcquiredBufferCount(currentMaxAcquiredBuffersCount), + eventStats(frameEventStats), + jankData(std::move(jankData)), + previousReleaseCallbackId(previousReleaseCallbackId) {} + + sp surfaceControl; + std::variant> acquireTimeOrFence = -1; + sp previousReleaseFence; + std::optional transformHint = 0; + uint32_t currentMaxAcquiredBufferCount = 0; + FrameEventHistoryStats eventStats; + std::vector jankData; + ReleaseCallbackId previousReleaseCallbackId; +}; + +class TransactionStats : public Parcelable { +public: + status_t writeToParcel(Parcel* output) const override; + status_t readFromParcel(const Parcel* input) override; + + TransactionStats() = default; + TransactionStats(const std::vector& ids) : callbackIds(ids) {} + TransactionStats(const std::unordered_set& ids) + : callbackIds(ids.begin(), ids.end()) {} + TransactionStats(const std::vector& ids, nsecs_t latch, const sp& present, + const std::vector& surfaces) + : callbackIds(ids), latchTime(latch), presentFence(present), surfaceStats(surfaces) {} + + std::vector callbackIds; + nsecs_t latchTime = -1; + sp presentFence = nullptr; + std::vector surfaceStats; +}; + +class ListenerStats : public Parcelable { +public: + status_t writeToParcel(Parcel* output) const override; + status_t readFromParcel(const Parcel* input) override; + + static ListenerStats createEmpty( + const sp& listener, + const std::unordered_set& callbackIds); + + sp listener; + std::vector transactionStats; +}; + +class ITransactionCompletedListener : public IInterface { +public: + DECLARE_META_INTERFACE(TransactionCompletedListener) + + virtual void onTransactionCompleted(ListenerStats stats) = 0; + + virtual void onReleaseBuffer(ReleaseCallbackId callbackId, sp releaseFence, + uint32_t currentMaxAcquiredBufferCount) = 0; + + virtual void onTransactionQueueStalled(const String8& name) = 0; +}; + +class BnTransactionCompletedListener : public SafeBnInterface { +public: + BnTransactionCompletedListener() + : SafeBnInterface("BnTransactionCompletedListener") {} + + status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, + uint32_t flags = 0) override; +}; + +class ListenerCallbacks { +public: + ListenerCallbacks(const sp& listener, + const std::unordered_set& callbacks) + : transactionCompletedListener(listener), + callbackIds(callbacks.begin(), callbacks.end()) {} + + ListenerCallbacks(const sp& listener, const std::vector& ids) + : transactionCompletedListener(listener), callbackIds(ids) {} + + bool operator==(const ListenerCallbacks& rhs) const { + if (transactionCompletedListener != rhs.transactionCompletedListener) { + return false; + } + if (callbackIds.empty()) { + return rhs.callbackIds.empty(); + } + return callbackIds.front().id == rhs.callbackIds.front().id; + } + + // Returns a new ListenerCallbacks filtered by type + ListenerCallbacks filter(CallbackId::Type type) const; + + sp transactionCompletedListener; + std::vector callbackIds; +}; + +struct IListenerHash { + std::size_t operator()(const sp& strongPointer) const { + return std::hash{}(strongPointer.get()); + } +}; + +struct CallbackIdsHash { + // CallbackId vectors have several properties that let us get away with this simple hash. + // 1) CallbackIds are never 0 so if something has gone wrong and our CallbackId vector is + // empty we can still hash 0. + // 2) CallbackId vectors for the same listener either are identical or contain none of the + // same members. It is sufficient to just check the first CallbackId in the vectors. If + // they match, they are the same. If they do not match, they are not the same. + std::size_t operator()(const std::vector& callbackIds) const { + return std::hash{}((callbackIds.empty()) ? 0 : callbackIds.front().id); + } +}; + +struct ListenerCallbacksHash { + std::size_t HashCombine(size_t value1, size_t value2) const { + return value1 ^ (value2 + 0x9e3779b9 + (value1 << 6) + (value1 >> 2)); + } + + std::size_t operator()(const ListenerCallbacks& listenerCallbacks) const { + struct IListenerHash listenerHasher; + struct CallbackIdsHash callbackIdsHasher; + + std::size_t listenerHash = listenerHasher(listenerCallbacks.transactionCompletedListener); + std::size_t callbackIdsHash = callbackIdsHasher(listenerCallbacks.callbackIds); + + return HashCombine(listenerHash, callbackIdsHash); + } +}; + +} // namespace android diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index c5fdf82d4f..45a84f6c66 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -21,10 +21,10 @@ #include #include -#include #include #include #include +#include #include #include @@ -35,7 +35,6 @@ #include #include #include -#include #include #include #include @@ -57,9 +56,6 @@ class Parcel; using gui::ISurfaceComposerClient; using gui::LayerMetadata; -using gui::ITransactionCompletedListener; -using gui::ReleaseCallbackId; - struct client_cache_t { wp token = nullptr; uint64_t id; diff --git a/libs/gui/include/gui/ListenerStats.h b/libs/gui/include/gui/ListenerStats.h deleted file mode 100644 index 3a12802146..0000000000 --- a/libs/gui/include/gui/ListenerStats.h +++ /dev/null @@ -1,225 +0,0 @@ -/* - * Copyright 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "JankInfo.h" - -#include -#include -#include -#include - -#include -#include - -#include -#include - -#include -#include -#include -#include - -namespace android::gui { - -class CallbackId : public Parcelable { -public: - int64_t id; - enum class Type : int32_t { ON_COMPLETE, ON_COMMIT } type; - - CallbackId() {} - CallbackId(int64_t id, Type type) : id(id), type(type) {} - status_t writeToParcel(Parcel* output) const override; - status_t readFromParcel(const Parcel* input) override; - - bool operator==(const CallbackId& rhs) const { return id == rhs.id && type == rhs.type; } -}; - -struct CallbackIdHash { - std::size_t operator()(const CallbackId& key) const { return std::hash()(key.id); } -}; - -struct ReleaseBufferCallbackIdHash { - std::size_t operator()(const ReleaseCallbackId& key) const { - return std::hash()(key.bufferId); - } -}; - -class FrameEventHistoryStats : public Parcelable { -public: - status_t writeToParcel(Parcel* output) const override; - status_t readFromParcel(const Parcel* input) override; - - FrameEventHistoryStats() = default; - FrameEventHistoryStats(uint64_t fn, const sp& gpuCompFence, CompositorTiming compTiming, - nsecs_t refreshTime, nsecs_t dequeueReadyTime) - : frameNumber(fn), - gpuCompositionDoneFence(gpuCompFence), - compositorTiming(compTiming), - refreshStartTime(refreshTime), - dequeueReadyTime(dequeueReadyTime) {} - - uint64_t frameNumber; - sp gpuCompositionDoneFence; - CompositorTiming compositorTiming; - nsecs_t refreshStartTime; - nsecs_t dequeueReadyTime; -}; - -/** - * Jank information representing SurfaceFlinger's jank classification about frames for a specific - * surface. - */ -class JankData : public Parcelable { -public: - status_t writeToParcel(Parcel* output) const override; - status_t readFromParcel(const Parcel* input) override; - - JankData(); - JankData(int64_t frameVsyncId, int32_t jankType) - : frameVsyncId(frameVsyncId), jankType(jankType) {} - - // Identifier for the frame submitted with Transaction.setFrameTimelineVsyncId - int64_t frameVsyncId; - - // Bitmask of janks that occurred - int32_t jankType; -}; - -class SurfaceStats : public Parcelable { -public: - status_t writeToParcel(Parcel* output) const override; - status_t readFromParcel(const Parcel* input) override; - - SurfaceStats() = default; - SurfaceStats(const sp& sc, std::variant> acquireTimeOrFence, - const sp& prevReleaseFence, std::optional hint, - uint32_t currentMaxAcquiredBuffersCount, FrameEventHistoryStats frameEventStats, - std::vector jankData, ReleaseCallbackId previousReleaseCallbackId) - : surfaceControl(sc), - acquireTimeOrFence(std::move(acquireTimeOrFence)), - previousReleaseFence(prevReleaseFence), - transformHint(hint), - currentMaxAcquiredBufferCount(currentMaxAcquiredBuffersCount), - eventStats(frameEventStats), - jankData(std::move(jankData)), - previousReleaseCallbackId(previousReleaseCallbackId) {} - - sp surfaceControl; - std::variant> acquireTimeOrFence = -1; - sp previousReleaseFence; - std::optional transformHint = 0; - uint32_t currentMaxAcquiredBufferCount = 0; - FrameEventHistoryStats eventStats; - std::vector jankData; - ReleaseCallbackId previousReleaseCallbackId; -}; - -class TransactionStats : public Parcelable { -public: - status_t writeToParcel(Parcel* output) const override; - status_t readFromParcel(const Parcel* input) override; - - TransactionStats() = default; - TransactionStats(const std::vector& ids) : callbackIds(ids) {} - TransactionStats(const std::unordered_set& ids) - : callbackIds(ids.begin(), ids.end()) {} - TransactionStats(const std::vector& ids, nsecs_t latch, const sp& present, - const std::vector& surfaces) - : callbackIds(ids), latchTime(latch), presentFence(present), surfaceStats(surfaces) {} - - std::vector callbackIds; - nsecs_t latchTime = -1; - sp presentFence = nullptr; - std::vector surfaceStats; -}; - -class ListenerStats : public Parcelable { -public: - status_t writeToParcel(Parcel* output) const override; - status_t readFromParcel(const Parcel* input) override; - - static ListenerStats createEmpty( - const sp& listener, - const std::unordered_set& callbackIds); - - sp listener; - std::vector transactionStats; -}; - -class ListenerCallbacks { -public: - ListenerCallbacks(const sp& listener, - const std::unordered_set& callbacks) - : transactionCompletedListener(listener), - callbackIds(callbacks.begin(), callbacks.end()) {} - - ListenerCallbacks(const sp& listener, const std::vector& ids) - : transactionCompletedListener(listener), callbackIds(ids) {} - - bool operator==(const ListenerCallbacks& rhs) const { - if (transactionCompletedListener != rhs.transactionCompletedListener) { - return false; - } - if (callbackIds.empty()) { - return rhs.callbackIds.empty(); - } - return callbackIds.front().id == rhs.callbackIds.front().id; - } - - // Returns a new ListenerCallbacks filtered by type - ListenerCallbacks filter(CallbackId::Type type) const; - - sp transactionCompletedListener; - std::vector callbackIds; -}; - -struct IListenerHash { - std::size_t operator()(const sp& strongPointer) const { - return std::hash{}(strongPointer.get()); - } -}; - -struct CallbackIdsHash { - // CallbackId vectors have several properties that let us get away with this simple hash. - // 1) CallbackIds are never 0 so if something has gone wrong and our CallbackId vector is - // empty we can still hash 0. - // 2) CallbackId vectors for the same listener either are identical or contain none of the - // same members. It is sufficient to just check the first CallbackId in the vectors. If - // they match, they are the same. If they do not match, they are not the same. - std::size_t operator()(const std::vector& callbackIds) const { - return std::hash{}((callbackIds.empty()) ? 0 : callbackIds.front().id); - } -}; - -struct ListenerCallbacksHash { - std::size_t HashCombine(size_t value1, size_t value2) const { - return value1 ^ (value2 + 0x9e3779b9 + (value1 << 6) + (value1 >> 2)); - } - - std::size_t operator()(const ListenerCallbacks& listenerCallbacks) const { - struct IListenerHash listenerHasher; - struct CallbackIdsHash callbackIdsHasher; - - std::size_t listenerHash = listenerHasher(listenerCallbacks.transactionCompletedListener); - std::size_t callbackIdsHash = callbackIdsHasher(listenerCallbacks.callbackIds); - - return HashCombine(listenerHash, callbackIdsHash); - } -}; - -} // namespace android::gui diff --git a/libs/gui/include/gui/ReleaseCallbackId.h b/libs/gui/include/gui/ReleaseCallbackId.h deleted file mode 100644 index 142ee5a727..0000000000 --- a/libs/gui/include/gui/ReleaseCallbackId.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include - -#include - -namespace android::gui { - -class ReleaseCallbackId : public Parcelable { -public: - static const ReleaseCallbackId INVALID_ID; - - uint64_t bufferId; - uint64_t framenumber; - ReleaseCallbackId() {} - ReleaseCallbackId(uint64_t bufferId, uint64_t framenumber) - : bufferId(bufferId), framenumber(framenumber) {} - status_t writeToParcel(Parcel* output) const override; - status_t readFromParcel(const Parcel* input) override; - - bool operator==(const ReleaseCallbackId& rhs) const { - return bufferId == rhs.bufferId && framenumber == rhs.framenumber; - } - bool operator!=(const ReleaseCallbackId& rhs) const { return !operator==(rhs); } - std::string to_string() const { - if (*this == INVALID_ID) return "INVALID_ID"; - - return "bufferId:" + std::to_string(bufferId) + - " framenumber:" + std::to_string(framenumber); - } -}; - -} // namespace android::gui diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 96d3a23bec..df47002b3b 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -42,13 +42,10 @@ #include -#include - #include #include +#include #include -#include -#include #include #include #include @@ -62,21 +59,11 @@ class IGraphicBufferProducer; class ITunnelModeEnabledListener; class Region; -using gui::BnTransactionCompletedListener; -using gui::CallbackId; -using gui::CallbackIdHash; using gui::DisplayCaptureArgs; -using gui::FrameEventHistoryStats; using gui::IRegionSamplingListener; using gui::ISurfaceComposerClient; -using gui::ITransactionCompletedListener; -using gui::JankData; using gui::LayerCaptureArgs; using gui::LayerMetadata; -using gui::ListenerStats; -using gui::ReleaseBufferCallbackIdHash; -using gui::ReleaseCallbackId; -using gui::SurfaceStats; struct SurfaceControlStats { SurfaceControlStats(const sp& sc, nsecs_t latchTime, @@ -838,17 +825,17 @@ public: void setReleaseBufferCallback(const ReleaseCallbackId&, ReleaseBufferCallback); // BnTransactionCompletedListener overrides - binder::Status onTransactionCompleted(const ListenerStats& stats) override; - binder::Status onReleaseBuffer(const ReleaseCallbackId& callbackId, - const std::optional& releaseFenceFd, - int32_t currentMaxAcquiredBufferCount) override; - binder::Status onTransactionQueueStalled(const std::string& reason) override; + void onTransactionCompleted(ListenerStats stats) override; + void onReleaseBuffer(ReleaseCallbackId, sp releaseFence, + uint32_t currentMaxAcquiredBufferCount) override; void removeReleaseBufferCallback(const ReleaseCallbackId& callbackId); // For Testing Only static void setInstance(const sp&); + void onTransactionQueueStalled(const String8& reason) override; + private: ReleaseBufferCallback popReleaseBufferCallbackLocked(const ReleaseCallbackId&); static sp sInstance; diff --git a/services/surfaceflinger/FrontEnd/TransactionHandler.cpp b/services/surfaceflinger/FrontEnd/TransactionHandler.cpp index c2109b3aa5..8629671214 100644 --- a/services/surfaceflinger/FrontEnd/TransactionHandler.cpp +++ b/services/surfaceflinger/FrontEnd/TransactionHandler.cpp @@ -177,7 +177,7 @@ void TransactionHandler::onTransactionQueueStalled(uint64_t transactionId, } mStalledTransactions.push_back(transactionId); - listener->onTransactionQueueStalled(reason); + listener->onTransactionQueueStalled(String8(reason.c_str())); } void TransactionHandler::removeFromStalledTransactions(uint64_t id) { diff --git a/services/surfaceflinger/FrontEnd/TransactionHandler.h b/services/surfaceflinger/FrontEnd/TransactionHandler.h index 475ff1b1dc..a06b870549 100644 --- a/services/surfaceflinger/FrontEnd/TransactionHandler.h +++ b/services/surfaceflinger/FrontEnd/TransactionHandler.h @@ -29,7 +29,6 @@ namespace android { class TestableSurfaceFlinger; -using gui::IListenerHash; namespace surfaceflinger::frontend { class TransactionHandler { diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 56abc516fd..0017af0476 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -2604,12 +2604,9 @@ void Layer::callReleaseBufferCallback(const sp& l return; } ATRACE_FORMAT_INSTANT("callReleaseBufferCallback %s - %" PRIu64, getDebugName(), framenumber); - std::optional fenceFd; - if (releaseFence) { - fenceFd = os::ParcelFileDescriptor(base::unique_fd(::dup(releaseFence->get()))); - } - listener->onReleaseBuffer({buffer->getId(), framenumber}, fenceFd, - static_cast(currentMaxAcquiredBufferCount)); + listener->onReleaseBuffer({buffer->getId(), framenumber}, + releaseFence ? releaseFence : Fence::NO_FENCE, + currentMaxAcquiredBufferCount); } void Layer::onLayerDisplayed(ftl::SharedFuture futureFenceResult) { diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 55644e2a41..d4c4fb28f5 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -7113,7 +7113,8 @@ std::shared_ptr SurfaceFlinger::getExternalTextur layerName, static_cast(mMaxRenderTargetSize)); ALOGD("%s", errorMessage.c_str()); if (bufferData.releaseBufferListener) { - bufferData.releaseBufferListener->onTransactionQueueStalled(errorMessage); + bufferData.releaseBufferListener->onTransactionQueueStalled( + String8(errorMessage.c_str())); } return nullptr; } @@ -7131,7 +7132,7 @@ std::shared_ptr SurfaceFlinger::getExternalTextur if (bufferData.releaseBufferListener) { bufferData.releaseBufferListener->onTransactionQueueStalled( - "Buffer processing hung due to full buffer cache"); + String8("Buffer processing hung due to full buffer cache")); } } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 8fa427843b..3354b24bbb 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include @@ -35,8 +34,8 @@ #include #include #include +#include #include - #include #include #include @@ -126,9 +125,7 @@ using frontend::TransactionHandler; using gui::CaptureArgs; using gui::DisplayCaptureArgs; using gui::IRegionSamplingListener; -using gui::ITransactionCompletedListener; using gui::LayerCaptureArgs; - using gui::ScreenCaptureResults; namespace frametimeline { diff --git a/services/surfaceflinger/TransactionCallbackInvoker.h b/services/surfaceflinger/TransactionCallbackInvoker.h index c09bcce067..61ff9bce98 100644 --- a/services/surfaceflinger/TransactionCallbackInvoker.h +++ b/services/surfaceflinger/TransactionCallbackInvoker.h @@ -26,27 +26,14 @@ #include #include -#include - #include -#include -#include -#include +#include +#include #include #include namespace android { -using gui::CallbackId; -using gui::FrameEventHistoryStats; -using gui::IListenerHash; -using gui::ITransactionCompletedListener; -using gui::JankData; -using gui::ListenerCallbacks; -using gui::ListenerStats; -using gui::ReleaseCallbackId; -using gui::TransactionStats; - class CallbackHandle : public RefBase { public: CallbackHandle(const sp& transactionListener, const std::vector& ids, -- cgit v1.2.3-59-g8ed1b From 076acace33a13f588d3e7450872e738bc1fa3f06 Mon Sep 17 00:00:00 2001 From: Chavi Weingarten Date: Thu, 19 Jan 2023 17:20:43 +0000 Subject: SurfaceFlinger: Add TrustedPresentationListener API TrustedPresentationListener is intended to allow the producer of a buffer layer to gain a trusted signal on whether and to what extent a layer is presented. A strawman design would be to provide the producer details on it's presentation (alpha, position, scale, final crop, covered region, etc). In the strawman design the client end would then decide itself whether each of these parameters were in an acceptable range. However providing the client feedback on it's per frame position would have a negative system health impact. Furthermore in some of the target use cases we can't even be sure the layer of interest is actively producing buffers and so there may be no existing callback to piggy-back on. Because of this we use a server side thresholding approach, where the client expresses some visibility threshold and a time stability constraint. See SurfaceComposerClient.h comment for details on these thresholds and their computation. Bug: 256993331 Test: LayerTrustedPresentationListener_test.cpp Change-Id: If4bef60dc6b22ce4959c353fa2a19b0994a00f5c --- libs/gui/ITransactionCompletedListener.cpp | 11 +- libs/gui/LayerState.cpp | 27 +++ libs/gui/SurfaceComposerClient.cpp | 80 +++++++ .../android/gui/TrustedPresentationThresholds.aidl | 24 ++ .../include/gui/ITransactionCompletedListener.h | 2 + libs/gui/include/gui/LayerState.h | 21 +- libs/gui/include/gui/SurfaceComposerClient.h | 72 ++++++ services/surfaceflinger/Layer.cpp | 104 +++++++++ services/surfaceflinger/Layer.h | 22 ++ services/surfaceflinger/Scheduler/MessageQueue.cpp | 4 + services/surfaceflinger/Scheduler/MessageQueue.h | 2 + services/surfaceflinger/Scheduler/Scheduler.h | 7 + services/surfaceflinger/SurfaceFlinger.cpp | 24 +- services/surfaceflinger/SurfaceFlinger.h | 6 +- .../fuzzer/surfaceflinger_fuzzers_utils.h | 2 +- services/surfaceflinger/tests/Android.bp | 1 + .../LayerTrustedPresentationListener_test.cpp | 241 +++++++++++++++++++++ 17 files changed, 644 insertions(+), 6 deletions(-) create mode 100644 libs/gui/aidl/android/gui/TrustedPresentationThresholds.aidl create mode 100644 services/surfaceflinger/tests/LayerTrustedPresentationListener_test.cpp (limited to 'libs/gui/LayerState.cpp') diff --git a/libs/gui/ITransactionCompletedListener.cpp b/libs/gui/ITransactionCompletedListener.cpp index 2b25b614e9..985c54922d 100644 --- a/libs/gui/ITransactionCompletedListener.cpp +++ b/libs/gui/ITransactionCompletedListener.cpp @@ -33,7 +33,8 @@ enum class Tag : uint32_t { ON_TRANSACTION_COMPLETED = IBinder::FIRST_CALL_TRANSACTION, ON_RELEASE_BUFFER, ON_TRANSACTION_QUEUE_STALLED, - LAST = ON_TRANSACTION_QUEUE_STALLED, + ON_TRUSTED_PRESENTATION_CHANGED, + LAST = ON_TRUSTED_PRESENTATION_CHANGED, }; } // Anonymous namespace @@ -302,6 +303,11 @@ public: onTransactionQueueStalled)>(Tag::ON_TRANSACTION_QUEUE_STALLED, reason); } + + void onTrustedPresentationChanged(int id, bool inTrustedPresentationState) override { + callRemoteAsync( + Tag::ON_TRUSTED_PRESENTATION_CHANGED, id, inTrustedPresentationState); + } }; // Out-of-line virtual method definitions to trigger vtable emission in this translation unit (see @@ -325,6 +331,9 @@ status_t BnTransactionCompletedListener::onTransact(uint32_t code, const Parcel& case Tag::ON_TRANSACTION_QUEUE_STALLED: return callLocalAsync(data, reply, &ITransactionCompletedListener::onTransactionQueueStalled); + case Tag::ON_TRUSTED_PRESENTATION_CHANGED: + return callLocalAsync(data, reply, + &ITransactionCompletedListener::onTrustedPresentationChanged); } } diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 59b62fe58c..43acb16299 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -185,6 +185,8 @@ status_t layer_state_t::write(Parcel& output) const if (hasBufferData) { SAFE_PARCEL(output.writeParcelable, *bufferData); } + SAFE_PARCEL(output.writeParcelable, trustedPresentationThresholds); + SAFE_PARCEL(output.writeParcelable, trustedPresentationListener); return NO_ERROR; } @@ -315,6 +317,10 @@ status_t layer_state_t::read(const Parcel& input) } else { bufferData = nullptr; } + + SAFE_PARCEL(input.readParcelable, &trustedPresentationThresholds); + SAFE_PARCEL(input.readParcelable, &trustedPresentationListener); + return NO_ERROR; } @@ -553,6 +559,11 @@ void layer_state_t::merge(const layer_state_t& other) { what |= eBufferChanged; bufferData = other.bufferData; } + if (other.what & eTrustedPresentationInfoChanged) { + what |= eTrustedPresentationInfoChanged; + trustedPresentationListener = other.trustedPresentationListener; + trustedPresentationThresholds = other.trustedPresentationThresholds; + } if (other.what & eDataspaceChanged) { what |= eDataspaceChanged; dataspace = other.dataspace; @@ -998,4 +1009,20 @@ status_t BufferData::readFromParcel(const Parcel* input) { return NO_ERROR; } +status_t TrustedPresentationListener::writeToParcel(Parcel* parcel) const { + SAFE_PARCEL(parcel->writeStrongBinder, callbackInterface); + SAFE_PARCEL(parcel->writeInt32, callbackId); + return NO_ERROR; +} + +status_t TrustedPresentationListener::readFromParcel(const Parcel* parcel) { + sp tmpBinder = nullptr; + SAFE_PARCEL(parcel->readNullableStrongBinder, &tmpBinder); + if (tmpBinder) { + callbackInterface = checked_interface_cast(tmpBinder); + } + SAFE_PARCEL(parcel->readInt32, &callbackId); + return NO_ERROR; +} + }; // namespace android diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 92125ead1f..732a168daa 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -63,6 +64,7 @@ namespace android { using aidl::android::hardware::graphics::common::DisplayDecorationSupport; using gui::FocusRequest; using gui::IRegionSamplingListener; +using gui::TrustedPresentationThresholds; using gui::WindowInfo; using gui::WindowInfoHandle; using gui::WindowInfosListener; @@ -518,6 +520,45 @@ void TransactionCompletedListener::removeReleaseBufferCallback( } } +SurfaceComposerClient::PresentationCallbackRAII::PresentationCallbackRAII( + TransactionCompletedListener* tcl, int id) { + mTcl = tcl; + mId = id; +} + +SurfaceComposerClient::PresentationCallbackRAII::~PresentationCallbackRAII() { + mTcl->clearTrustedPresentationCallback(mId); +} + +sp +TransactionCompletedListener::addTrustedPresentationCallback(TrustedPresentationCallback tpc, + int id, void* context) { + std::scoped_lock lock(mMutex); + mTrustedPresentationCallbacks[id] = + std::tuple(tpc, context); + return new SurfaceComposerClient::PresentationCallbackRAII(this, id); +} + +void TransactionCompletedListener::clearTrustedPresentationCallback(int id) { + std::scoped_lock lock(mMutex); + mTrustedPresentationCallbacks.erase(id); +} + +void TransactionCompletedListener::onTrustedPresentationChanged(int id, + bool presentedWithinThresholds) { + TrustedPresentationCallback tpc; + void* context; + { + std::scoped_lock lock(mMutex); + auto it = mTrustedPresentationCallbacks.find(id); + if (it == mTrustedPresentationCallbacks.end()) { + return; + } + std::tie(tpc, context) = it->second; + } + tpc(context, presentedWithinThresholds); +} + // --------------------------------------------------------------------------- void removeDeadBufferCallback(void* /*context*/, uint64_t graphicBufferId); @@ -2098,6 +2139,45 @@ void SurfaceComposerClient::Transaction::clearFrameTimelineInfo(FrameTimelineInf t.startTimeNanos = 0; } +SurfaceComposerClient::Transaction& +SurfaceComposerClient::Transaction::setTrustedPresentationCallback( + const sp& sc, TrustedPresentationCallback cb, + const TrustedPresentationThresholds& thresholds, void* context, + sp& outCallbackRef) { + auto listener = TransactionCompletedListener::getInstance(); + outCallbackRef = listener->addTrustedPresentationCallback(cb, sc->getLayerId(), context); + + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } + s->what |= layer_state_t::eTrustedPresentationInfoChanged; + s->trustedPresentationThresholds = thresholds; + s->trustedPresentationListener.callbackInterface = TransactionCompletedListener::getIInstance(); + s->trustedPresentationListener.callbackId = sc->getLayerId(); + + return *this; +} + +SurfaceComposerClient::Transaction& +SurfaceComposerClient::Transaction::clearTrustedPresentationCallback(const sp& sc) { + auto listener = TransactionCompletedListener::getInstance(); + listener->clearTrustedPresentationCallback(sc->getLayerId()); + + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } + s->what |= layer_state_t::eTrustedPresentationInfoChanged; + s->trustedPresentationThresholds = TrustedPresentationThresholds(); + s->trustedPresentationListener.callbackInterface = nullptr; + s->trustedPresentationListener.callbackId = -1; + + return *this; +} + // --------------------------------------------------------------------------- SurfaceComposerClient::SurfaceComposerClient() : mStatus(NO_INIT) {} diff --git a/libs/gui/aidl/android/gui/TrustedPresentationThresholds.aidl b/libs/gui/aidl/android/gui/TrustedPresentationThresholds.aidl new file mode 100644 index 0000000000..1eea5b44a4 --- /dev/null +++ b/libs/gui/aidl/android/gui/TrustedPresentationThresholds.aidl @@ -0,0 +1,24 @@ +/* + * Copyright 2022 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; + +parcelable TrustedPresentationThresholds { + float minAlpha = -1.0f; + float minFractionRendered = -1.0f; + + int stabilityRequirementMs = 0; +} diff --git a/libs/gui/include/gui/ITransactionCompletedListener.h b/libs/gui/include/gui/ITransactionCompletedListener.h index 453e8f3ef5..d593f56c3a 100644 --- a/libs/gui/include/gui/ITransactionCompletedListener.h +++ b/libs/gui/include/gui/ITransactionCompletedListener.h @@ -196,6 +196,8 @@ public: uint32_t currentMaxAcquiredBufferCount) = 0; virtual void onTransactionQueueStalled(const String8& name) = 0; + + virtual void onTrustedPresentationChanged(int id, bool inTrustedPresentationState) = 0; }; class BnTransactionCompletedListener : public SafeBnInterface { diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index 45a84f6c66..17ed2d84fa 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -56,6 +57,8 @@ class Parcel; using gui::ISurfaceComposerClient; using gui::LayerMetadata; +using gui::TrustedPresentationThresholds; + struct client_cache_t { wp token = nullptr; uint64_t id; @@ -65,6 +68,19 @@ struct client_cache_t { bool isValid() const { return token != nullptr; } }; +class TrustedPresentationListener : public Parcelable { +public: + sp callbackInterface; + int callbackId = -1; + + void invoke(bool presentedWithinThresholds) { + callbackInterface->onTrustedPresentationChanged(callbackId, presentedWithinThresholds); + } + + status_t writeToParcel(Parcel* parcel) const; + status_t readFromParcel(const Parcel* parcel); +}; + class BufferData : public Parcelable { public: virtual ~BufferData() = default; @@ -148,7 +164,7 @@ struct layer_state_t { enum { ePositionChanged = 0x00000001, eLayerChanged = 0x00000002, - /* unused = 0x00000004, */ + eTrustedPresentationInfoChanged = 0x00000004, eAlphaChanged = 0x00000008, eMatrixChanged = 0x00000010, eTransparentRegionChanged = 0x00000020, @@ -339,6 +355,9 @@ struct layer_state_t { gui::DropInputMode dropInputMode; bool dimmingEnabled; + + TrustedPresentationThresholds trustedPresentationThresholds; + TrustedPresentationListener trustedPresentationListener; }; class ComposerState { diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 2458a40ce0..6c45b260df 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -58,6 +58,7 @@ class HdrCapabilities; class IGraphicBufferProducer; class ITunnelModeEnabledListener; class Region; +class TransactionCompletedListener; using gui::DisplayCaptureArgs; using gui::IRegionSamplingListener; @@ -106,6 +107,8 @@ using SurfaceStatsCallback = const sp& /*presentFence*/, const SurfaceStats& /*stats*/)>; +using TrustedPresentationCallback = std::function; + // --------------------------------------------------------------------------- class ReleaseCallbackThread { @@ -390,6 +393,13 @@ public: std::unordered_set, SCHash> surfaceControls; }; + struct PresentationCallbackRAII : public RefBase { + sp mTcl; + int mId; + PresentationCallbackRAII(TransactionCompletedListener* tcl, int id); + virtual ~PresentationCallbackRAII(); + }; + class Transaction : public Parcelable { private: static sp sApplyToken; @@ -569,6 +579,59 @@ public: Transaction& addTransactionCommittedCallback( TransactionCompletedCallbackTakesContext callback, void* callbackContext); + /** + * Set a callback to receive feedback about the presentation of a layer. + * When the layer is presented according to the passed in Thresholds, + * it is said to "enter the state", and receives the callback with true. + * When the conditions fall out of thresholds, it is then said to leave the + * state. + * + * There are a few simple thresholds: + * minAlpha: Lower bound on computed alpha + * minFractionRendered: Lower bounds on fraction of pixels that + * were rendered. + * stabilityThresholdMs: A time that alpha and fraction rendered + * must remain within bounds before we can "enter the state" + * + * The fraction of pixels rendered is a computation based on scale, crop + * and occlusion. The calculation may be somewhat counterintuitive, so we + * can work through an example. Imagine we have a layer with a 100x100 buffer + * which is occluded by (10x100) pixels on the left, and cropped by (100x10) pixels + * on the top. Furthermore imagine this layer is scaled by 0.9 in both dimensions. + * (c=crop,o=occluded,b=both,x=none + * b c c c + * o x x x + * o x x x + * o x x x + * + * We first start by computing fr=xscale*yscale=0.9*0.9=0.81, indicating + * that "81%" of the pixels were rendered. This corresponds to what was 100 + * pixels being displayed in 81 pixels. This is somewhat of an abuse of + * language, as the information of merged pixels isn't totally lost, but + * we err on the conservative side. + * + * We then repeat a similar process for the crop and covered regions and + * accumulate the results: fr = fr * (fractionNotCropped) * (fractionNotCovered) + * So for this example we would get 0.9*0.9*0.9*0.9=0.65... + * + * Notice that this is not completely accurate, as we have double counted + * the region marked as b. However we only wanted a "lower bound" and so it + * is ok to err in this direction. Selection of the threshold will ultimately + * be somewhat arbitrary, and so there are some somewhat arbitrary decisions in + * this API as well. + * + * The caller must keep "PresentationCallbackRAII" alive, or the callback + * in SurfaceComposerClient will be unregistered. + */ + Transaction& setTrustedPresentationCallback(const sp& sc, + TrustedPresentationCallback callback, + const TrustedPresentationThresholds& thresholds, + void* context, + sp& outCallbackOwner); + + // Clear local memory in SCC + Transaction& clearTrustedPresentationCallback(const sp& sc); + // ONLY FOR BLAST ADAPTER Transaction& notifyProducerDisconnect(const sp& sc); @@ -795,6 +858,9 @@ protected: std::multimap mSurfaceStatsListeners; std::unordered_map> mQueueStallListeners; + std::unordered_map> + mTrustedPresentationCallbacks; + public: static sp getInstance(); static sp getIInstance(); @@ -814,6 +880,10 @@ public: void addQueueStallListener(std::function stallListener, void* id); void removeQueueStallListener(void *id); + sp addTrustedPresentationCallback( + TrustedPresentationCallback tpc, int id, void* context); + void clearTrustedPresentationCallback(int id); + /* * Adds a jank listener to be informed about SurfaceFlinger's jank classification for a specific * surface. Jank classifications arrive as part of the transaction callbacks about previous @@ -844,6 +914,8 @@ public: void onTransactionQueueStalled(const String8& reason) override; + void onTrustedPresentationChanged(int id, bool presentedWithinThresholds) override; + private: ReleaseBufferCallback popReleaseBufferCallbackLocked(const ReleaseCallbackId&); static sp sInstance; diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index de9ea0420c..6197e9bb47 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -250,6 +250,10 @@ Layer::~Layer() { if (mHadClonedChild) { mFlinger->mNumClones--; } + if (hasTrustedPresentationListener()) { + mFlinger->mNumTrustedPresentationListeners--; + updateTrustedPresentationState(nullptr, -1 /* time_in_ms */, true /* leaveState*/); + } } // --------------------------------------------------------------------------- @@ -279,6 +283,7 @@ void Layer::removeFromCurrentState() { mRemovedFromDrawingState = true; mFlinger->mScheduler->deregisterLayer(this); } + updateTrustedPresentationState(nullptr, -1 /* time_in_ms */, true /* leaveState*/); mFlinger->markLayerPendingRemovalLocked(sp::fromExisting(this)); } @@ -376,6 +381,92 @@ FloatRect Layer::getBounds(const Region& activeTransparentRegion) const { return reduce(mBounds, activeTransparentRegion); } +// No early returns. +void Layer::updateTrustedPresentationState(const DisplayDevice* display, int64_t time_in_ms, + bool leaveState) { + if (!hasTrustedPresentationListener()) { + return; + } + const bool lastState = mLastComputedTrustedPresentationState; + mLastComputedTrustedPresentationState = false; + + if (!leaveState) { + const auto outputLayer = findOutputLayerForDisplay(display); + if (outputLayer != nullptr) { + mLastComputedTrustedPresentationState = + computeTrustedPresentationState(mBounds, mSourceBounds, + outputLayer->getState().coveredRegion, + mScreenBounds, getCompositionState()->alpha, + getCompositionState()->geomLayerTransform, + mTrustedPresentationThresholds); + } + } + const bool newState = mLastComputedTrustedPresentationState; + if (lastState && !newState) { + // We were in the trusted presentation state, but now we left it, + // emit the callback if needed + if (mLastReportedTrustedPresentationState) { + mLastReportedTrustedPresentationState = false; + mTrustedPresentationListener.invoke(false); + } + // Reset the timer + mEnteredTrustedPresentationStateTime = -1; + } else if (!lastState && newState) { + // We were not in the trusted presentation state, but we entered it, begin the timer + // and make sure this gets called at least once more! + mEnteredTrustedPresentationStateTime = time_in_ms; + mFlinger->forceFutureUpdate(mTrustedPresentationThresholds.stabilityRequirementMs * 1.5); + } + + // Has the timer elapsed, but we are still in the state? Emit a callback if needed + if (!mLastReportedTrustedPresentationState && newState && + (time_in_ms - mEnteredTrustedPresentationStateTime > + mTrustedPresentationThresholds.stabilityRequirementMs)) { + mLastReportedTrustedPresentationState = true; + mTrustedPresentationListener.invoke(true); + } +} + +/** + * See SurfaceComposerClient.h: setTrustedPresentationCallback for discussion + * of how the parameters and thresholds are interpreted. The general spirit is + * to produce an upper bound on the amount of the buffer which was presented. + */ +bool Layer::computeTrustedPresentationState(const FloatRect& bounds, const FloatRect& sourceBounds, + const Region& coveredRegion, + const FloatRect& screenBounds, float alpha, + const ui::Transform& effectiveTransform, + const TrustedPresentationThresholds& thresholds) { + if (alpha < thresholds.minAlpha) { + return false; + } + if (sourceBounds.getWidth() == 0 || sourceBounds.getHeight() == 0) { + return false; + } + if (screenBounds.getWidth() == 0 || screenBounds.getHeight() == 0) { + return false; + } + + const float sx = effectiveTransform.dsdx(); + const float sy = effectiveTransform.dsdy(); + float fractionRendered = std::min(sx * sy, 1.0f); + + float boundsOverSourceW = bounds.getWidth() / (float)sourceBounds.getWidth(); + float boundsOverSourceH = bounds.getHeight() / (float)sourceBounds.getHeight(); + fractionRendered *= boundsOverSourceW * boundsOverSourceH; + + Rect coveredBounds = coveredRegion.bounds(); + fractionRendered *= (1 - + ((coveredBounds.width() / (float)screenBounds.getWidth()) * + coveredBounds.height() / (float)screenBounds.getHeight())); + + if (fractionRendered < thresholds.minFractionRendered) { + return false; + } + + return true; +} + void Layer::computeBounds(FloatRect parentBounds, ui::Transform parentTransform, float parentShadowRadius) { const State& s(getDrawingState()); @@ -3988,6 +4079,19 @@ LayerSnapshotGuard& LayerSnapshotGuard::operator=(LayerSnapshotGuard&& other) { return *this; } +void Layer::setTrustedPresentationInfo(TrustedPresentationThresholds const& thresholds, + TrustedPresentationListener const& listener) { + bool hadTrustedPresentationListener = hasTrustedPresentationListener(); + mTrustedPresentationListener = listener; + mTrustedPresentationThresholds = thresholds; + bool haveTrustedPresentationListener = hasTrustedPresentationListener(); + if (!hadTrustedPresentationListener && haveTrustedPresentationListener) { + mFlinger->mNumTrustedPresentationListeners++; + } else if (hadTrustedPresentationListener && !haveTrustedPresentationListener) { + mFlinger->mNumTrustedPresentationListeners--; + } +} + // --------------------------------------------------------------------------- std::ostream& operator<<(std::ostream& stream, const Layer::FrameRate& rate) { diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 08a13a34eb..63894cd83d 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -527,6 +527,19 @@ public: uint32_t getTransactionFlags() const { return mTransactionFlags; } + static bool computeTrustedPresentationState(const FloatRect& bounds, + const FloatRect& sourceBounds, + const Region& coveredRegion, + const FloatRect& screenBounds, float, + const ui::Transform&, + const TrustedPresentationThresholds&); + void updateTrustedPresentationState(const DisplayDevice* display, int64_t time_in_ms, + bool leaveState); + + inline bool hasTrustedPresentationListener() { + return mTrustedPresentationListener.callbackInterface != nullptr; + } + // Sets the masked bits. void setTransactionFlags(uint32_t mask); @@ -728,6 +741,9 @@ public: std::shared_ptr createSurfaceFrameForBuffer( const FrameTimelineInfo& info, nsecs_t queueTime, std::string debugName); + void setTrustedPresentationInfo(TrustedPresentationThresholds const& thresholds, + TrustedPresentationListener const& listener); + // Creates a new handle each time, so we only expect // this to be called once. sp getHandle(); @@ -883,6 +899,12 @@ protected: // These are only accessed by the main thread or the tracing thread. State mDrawingState; + TrustedPresentationThresholds mTrustedPresentationThresholds; + TrustedPresentationListener mTrustedPresentationListener; + bool mLastComputedTrustedPresentationState = false; + bool mLastReportedTrustedPresentationState = false; + int64_t mEnteredTrustedPresentationStateTime = -1; + uint32_t mTransactionFlags{0}; // Updated in doTransaction, used to track the last sequence number we // committed. Currently this is really only used for updating visible diff --git a/services/surfaceflinger/Scheduler/MessageQueue.cpp b/services/surfaceflinger/Scheduler/MessageQueue.cpp index e827c12f7c..9b044977be 100644 --- a/services/surfaceflinger/Scheduler/MessageQueue.cpp +++ b/services/surfaceflinger/Scheduler/MessageQueue.cpp @@ -132,6 +132,10 @@ void MessageQueue::postMessage(sp&& handler) { mLooper->sendMessage(handler, Message()); } +void MessageQueue::postMessageDelayed(sp&& handler, nsecs_t uptimeDelay) { + mLooper->sendMessageDelayed(uptimeDelay, handler, Message()); +} + void MessageQueue::scheduleConfigure() { struct ConfigureHandler : MessageHandler { explicit ConfigureHandler(ICompositor& compositor) : compositor(compositor) {} diff --git a/services/surfaceflinger/Scheduler/MessageQueue.h b/services/surfaceflinger/Scheduler/MessageQueue.h index 71f8645828..ad0ea72623 100644 --- a/services/surfaceflinger/Scheduler/MessageQueue.h +++ b/services/surfaceflinger/Scheduler/MessageQueue.h @@ -79,6 +79,7 @@ public: virtual void setDuration(std::chrono::nanoseconds workDuration) = 0; virtual void waitMessage() = 0; virtual void postMessage(sp&&) = 0; + virtual void postMessageDelayed(sp&&, nsecs_t uptimeDelay) = 0; virtual void scheduleConfigure() = 0; virtual void scheduleFrame() = 0; @@ -144,6 +145,7 @@ public: void waitMessage() override; void postMessage(sp&&) override; + void postMessageDelayed(sp&&, nsecs_t uptimeDelay) override; void scheduleConfigure() override; void scheduleFrame() override; diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index 20221d1907..36280e3888 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -139,6 +139,13 @@ public: return std::move(future); } + template > + [[nodiscard]] std::future scheduleDelayed(F&& f, nsecs_t uptimeDelay) { + auto [task, future] = makeTask(std::move(f)); + postMessageDelayed(std::move(task), uptimeDelay); + return std::move(future); + } + ConnectionHandle createConnection(const char* connectionName, frametimeline::TokenManager*, std::chrono::nanoseconds workDuration, std::chrono::nanoseconds readyDuration); diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 2d8b9c1672..41e305e986 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2439,7 +2439,7 @@ void SurfaceFlinger::composite(TimePoint frameTime, VsyncId vsyncId) scheduleComposite(FrameHint::kNone); } - postComposition(); + postComposition(presentTime); const bool prevFrameHadClientComposition = mHadClientComposition; @@ -2553,7 +2553,7 @@ ui::Rotation SurfaceFlinger::getPhysicalDisplayOrientation(DisplayId displayId, return ui::ROTATION_0; } -void SurfaceFlinger::postComposition() { +void SurfaceFlinger::postComposition(nsecs_t callTime) { ATRACE_CALL(); ALOGV(__func__); @@ -2718,6 +2718,17 @@ void SurfaceFlinger::postComposition() { } } + if (mNumTrustedPresentationListeners > 0) { + // We avoid any reverse traversal upwards so this shouldn't be too expensive + mDrawingState.traverse([&](Layer* layer) { + if (!layer->hasTrustedPresentationListener()) { + return; + } + layer->updateTrustedPresentationState(display, nanoseconds_to_milliseconds(callTime), + false); + }); + } + // Even though ATRACE_INT64 already checks if tracing is enabled, it doesn't prevent the // side-effect of getTotalSize(), so we check that again here if (ATRACE_ENABLED()) { @@ -4593,6 +4604,11 @@ uint32_t SurfaceFlinger::setClientStateLocked(const FrameTimelineInfo& frameTime layer->setFrameTimelineVsyncForBufferlessTransaction(frameTimelineInfo, postTime); } + if (what & layer_state_t::eTrustedPresentationInfoChanged) { + layer->setTrustedPresentationInfo(s.trustedPresentationThresholds, + s.trustedPresentationListener); + } + if (layer->setTransactionCompletedListeners(callbackHandles)) flags |= eTraversalNeeded; // Do not put anything that updates layer state or modifies flags after // setTransactionCompletedListener @@ -8118,6 +8134,10 @@ status_t SurfaceComposerAIDL::checkReadFrameBufferPermission() { return OK; } +void SurfaceFlinger::forceFutureUpdate(int delayInMs) { + static_cast(mScheduler->scheduleDelayed([&]() { scheduleRepaint(); }, ms2ns(delayInMs))); +} + } // namespace android #if defined(__gl_h_) diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 33f0402094..b52dc82773 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -313,6 +313,8 @@ public: // TODO(b/246793311): Clean up a temporary property bool mIgnoreHwcPhysicalDisplayOrientation = false; + void forceFutureUpdate(int delayInMs); + protected: // We're reference counted, never destroy SurfaceFlinger directly virtual ~SurfaceFlinger(); @@ -926,7 +928,7 @@ private: /* * Compositing */ - void postComposition() REQUIRES(kMainThreadContext); + void postComposition(nsecs_t callTime) REQUIRES(kMainThreadContext); /* * Display management @@ -1274,6 +1276,8 @@ private: float mDimmingRatio = -1.f; std::unique_ptr mRenderEngine; + std::atomic mNumTrustedPresentationListeners = 0; + std::unique_ptr mCompositionEngine; // mMaxRenderTargetSize is only set once in init() so it doesn't need to be protected by // any mutex. diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h index 81ca659915..6b52a3ac13 100644 --- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h +++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h @@ -599,7 +599,7 @@ public: mFlinger->commitTransactions(); mFlinger->flushTransactionQueues(getFuzzedVsyncId(mFdp)); - mFlinger->postComposition(); + mFlinger->postComposition(systemTime()); } mFlinger->setTransactionFlags(mFdp.ConsumeIntegral()); diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp index bd6367d672..de47330216 100644 --- a/services/surfaceflinger/tests/Android.bp +++ b/services/surfaceflinger/tests/Android.bp @@ -43,6 +43,7 @@ cc_test { "LayerRenderTypeTransaction_test.cpp", "LayerState_test.cpp", "LayerTransaction_test.cpp", + "LayerTrustedPresentationListener_test.cpp", "LayerTypeAndRenderTypeTransaction_test.cpp", "LayerTypeTransaction_test.cpp", "LayerUpdate_test.cpp", diff --git a/services/surfaceflinger/tests/LayerTrustedPresentationListener_test.cpp b/services/surfaceflinger/tests/LayerTrustedPresentationListener_test.cpp new file mode 100644 index 0000000000..a843fd17b1 --- /dev/null +++ b/services/surfaceflinger/tests/LayerTrustedPresentationListener_test.cpp @@ -0,0 +1,241 @@ +/* + * Copyright (C) 2022 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. + */ + +// TODO(b/129481165): remove the #pragma below and fix conversion issues +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wconversion" + +#include +#include +#include +#include "TransactionTestHarnesses.h" + +namespace android { +struct PresentationCallbackHelper { + void callbackArrived(bool state) { + std::unique_lock l(mMutex); + mGotCallback = true; + mState = state; + mCondition.notify_all(); + } + bool awaitCallback() { + std::unique_lock l(mMutex); + mGotCallback = false; + mCondition.wait_for(l, 5000ms); + EXPECT_TRUE(mGotCallback); + return mState; + } + + bool mState; + bool mGotCallback; + std::mutex mMutex; + std::condition_variable mCondition; +}; + +TrustedPresentationThresholds thresh() { + TrustedPresentationThresholds thresholds; + thresholds.minAlpha = 1.0; + thresholds.minFractionRendered = 1.0; + thresholds.stabilityRequirementMs = 100; + return thresholds; +} + +class LayerTrustedPresentationListenerTest : public LayerTransactionTest { +public: + void SetUp() override { + LayerTransactionTest::SetUp(); + mainLayer = makeLayer(); + thresholds = thresh(); + } + + void TearDown() override { + LayerTransactionTest::TearDown(); + mCallback = nullptr; + t.reparent(mainLayer, nullptr).apply(); + mainLayer = nullptr; + } + + void thresholdsPrepared() { + t.show(mainLayer) + .setLayer(mainLayer, INT32_MAX) + .setTrustedPresentationCallback( + mainLayer, + [&](void* context, bool state) { + PresentationCallbackHelper* helper = + (PresentationCallbackHelper*)context; + helper->callbackArrived(state); + }, + thresholds, &pch, mCallback) + .setPosition(mainLayer, 100, 100) + .apply(); + } + + sp makeLayer() { + sp layer = + createLayer("test", 100, 100, ISurfaceComposerClient::eFXSurfaceBufferState, + mBlackBgSurface.get()); + fillBufferLayerColor(layer, Color::RED, 100, 100); + return layer; + } + sp mainLayer; + PresentationCallbackHelper pch; + SurfaceComposerClient::Transaction t; + TrustedPresentationThresholds thresholds; + sp mCallback; +}; + +// The layer is fully presented with the default test setup. +TEST_F(LayerTrustedPresentationListenerTest, callback_arrives) { + thresholdsPrepared(); + EXPECT_TRUE(pch.awaitCallback()); +} + +// A hidden layer can't be considered presented! +TEST_F(LayerTrustedPresentationListenerTest, hiding_layer_clears_state) { + thresholdsPrepared(); + EXPECT_TRUE(pch.awaitCallback()); + t.hide(mainLayer).apply(); + EXPECT_FALSE(pch.awaitCallback()); +} + +// A fully obscured layer can't be considered presented! +TEST_F(LayerTrustedPresentationListenerTest, obscuring_clears_state) { + thresholdsPrepared(); + EXPECT_TRUE(pch.awaitCallback()); + + auto otherLayer = makeLayer(); + t.show(otherLayer) + .setPosition(otherLayer, 100, 100) + .setLayer(otherLayer, INT32_MAX) + .setLayer(mainLayer, INT32_MAX - 1) + .apply(); + EXPECT_FALSE(pch.awaitCallback()); +} + +// Even if the layer obscuring us has an Alpha channel, we are still considered +// obscured. +TEST_F(LayerTrustedPresentationListenerTest, obscuring_with_transparency_clears_state) { + thresholdsPrepared(); + EXPECT_TRUE(pch.awaitCallback()); + + auto otherLayer = makeLayer(); + t.show(otherLayer) + .setPosition(otherLayer, 100, 100) + .setLayer(otherLayer, INT32_MAX) + .setFlags(otherLayer, 0, layer_state_t::eLayerOpaque) + .setLayer(mainLayer, INT32_MAX - 1) + .apply(); + EXPECT_FALSE(pch.awaitCallback()); +} + +// We can't be presented if our alpha is below the threshold. +TEST_F(LayerTrustedPresentationListenerTest, alpha_below_threshold) { + thresholdsPrepared(); + EXPECT_TRUE(pch.awaitCallback()); + t.setAlpha(mainLayer, 0.9).apply(); + EXPECT_FALSE(pch.awaitCallback()); + t.setAlpha(mainLayer, 1.0).apply(); + EXPECT_TRUE(pch.awaitCallback()); +} + +// Verify that the passed in threshold is actually respected! +TEST_F(LayerTrustedPresentationListenerTest, alpha_below_other_threshold) { + thresholds.minAlpha = 0.8; + thresholdsPrepared(); + EXPECT_TRUE(pch.awaitCallback()); + t.setAlpha(mainLayer, 0.8).apply(); + EXPECT_FALSE(pch.awaitCallback()); + t.setAlpha(mainLayer, 0.9).apply(); + EXPECT_TRUE(pch.awaitCallback()); +} + +// (86*86)/(100*100) = 0.73...so a crop of 86x86 is below the threshold +// (87*87)/(100*100) = 0.76...so a crop of 87x87 is above the threshold! +TEST_F(LayerTrustedPresentationListenerTest, crop_below_threshold) { + thresholds.minFractionRendered = 0.75; + thresholdsPrepared(); + EXPECT_TRUE(pch.awaitCallback()); + t.setCrop(mainLayer, Rect(0, 0, 86, 86)).apply(); + EXPECT_FALSE(pch.awaitCallback()); + t.setCrop(mainLayer, Rect(0, 0, 87, 87)).apply(); + EXPECT_TRUE(pch.awaitCallback()); +} + +TEST_F(LayerTrustedPresentationListenerTest, scale_below_threshold) { + thresholds.minFractionRendered = 0.64; + thresholdsPrepared(); + EXPECT_TRUE(pch.awaitCallback()); + // 0.8 = sqrt(0.64) + t.setMatrix(mainLayer, 0.79, 0, 0, 0.79).apply(); + EXPECT_FALSE(pch.awaitCallback()); + t.setMatrix(mainLayer, 0.81, 0, 0, 0.81).apply(); + EXPECT_TRUE(pch.awaitCallback()); +} + +TEST_F(LayerTrustedPresentationListenerTest, obscuring_with_threshold_1) { + thresholds.minFractionRendered = 0.75; + thresholdsPrepared(); + EXPECT_TRUE(pch.awaitCallback()); + + auto otherLayer = makeLayer(); + t.show(otherLayer) + .setPosition(otherLayer, 100, 100) + .setLayer(otherLayer, INT32_MAX) + .setLayer(mainLayer, INT32_MAX - 1) + .apply(); + EXPECT_FALSE(pch.awaitCallback()); + t.setMatrix(otherLayer, 0.49, 0, 0, 0.49).apply(); + EXPECT_TRUE(pch.awaitCallback()); + t.setMatrix(otherLayer, 0.51, 0, 0, 0.51).apply(); + EXPECT_FALSE(pch.awaitCallback()); +} + +TEST_F(LayerTrustedPresentationListenerTest, obscuring_with_threshold_2) { + thresholds.minFractionRendered = 0.9; + thresholdsPrepared(); + EXPECT_TRUE(pch.awaitCallback()); + + auto otherLayer = makeLayer(); + t.show(otherLayer) + .setPosition(otherLayer, 100, 100) + .setLayer(otherLayer, INT32_MAX) + .setLayer(mainLayer, INT32_MAX - 1) + .apply(); + EXPECT_FALSE(pch.awaitCallback()); + t.setMatrix(otherLayer, 0.3, 0, 0, 0.3).apply(); + EXPECT_TRUE(pch.awaitCallback()); + t.setMatrix(otherLayer, 0.33, 0, 0, 0.33).apply(); + EXPECT_FALSE(pch.awaitCallback()); +} + +TEST_F(LayerTrustedPresentationListenerTest, obscuring_with_alpha) { + thresholds.minFractionRendered = 0.9; + thresholdsPrepared(); + EXPECT_TRUE(pch.awaitCallback()); + + auto otherLayer = makeLayer(); + t.show(otherLayer) + .setPosition(otherLayer, 100, 100) + .setLayer(otherLayer, INT32_MAX) + .setLayer(mainLayer, INT32_MAX - 1) + .setAlpha(otherLayer, 0.01) + .apply(); + EXPECT_FALSE(pch.awaitCallback()); + t.setAlpha(otherLayer, 0.0).apply(); + EXPECT_TRUE(pch.awaitCallback()); +} + +} // namespace android -- cgit v1.2.3-59-g8ed1b From 6879659d589a17d362f91bba4bec5737504a75e7 Mon Sep 17 00:00:00 2001 From: John Reck Date: Wed, 25 Jan 2023 13:47:12 -0500 Subject: Add extended brightness range impl Bug: 241001465 Test: manual currently, flagged off Change-Id: I707281b9acaf6ea218f1d9ce888fc7cdbf1cf7c9 --- libs/gui/LayerState.cpp | 14 +++++++ libs/gui/SurfaceComposerClient.cpp | 15 +++++++ libs/gui/include/gui/LayerState.h | 8 +++- libs/gui/include/gui/SurfaceComposerClient.h | 2 + .../compositionengine/LayerFECompositionState.h | 3 ++ .../src/LayerFECompositionState.cpp | 4 ++ .../CompositionEngine/src/OutputLayer.cpp | 15 +++++-- .../FrontEnd/LayerSnapshotBuilder.cpp | 2 + .../FrontEnd/RequestedLayerState.cpp | 2 + services/surfaceflinger/HdrLayerInfoReporter.h | 25 +++++++++++ services/surfaceflinger/Layer.cpp | 27 +++++++++++- services/surfaceflinger/Layer.h | 8 +++- services/surfaceflinger/SurfaceFlinger.cpp | 48 ++++++++++++++-------- services/surfaceflinger/SurfaceFlinger.h | 8 ++-- 14 files changed, 153 insertions(+), 28 deletions(-) (limited to 'libs/gui/LayerState.cpp') diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 43acb16299..8372363185 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -187,6 +187,8 @@ status_t layer_state_t::write(Parcel& output) const } SAFE_PARCEL(output.writeParcelable, trustedPresentationThresholds); SAFE_PARCEL(output.writeParcelable, trustedPresentationListener); + SAFE_PARCEL(output.writeFloat, currentSdrHdrRatio); + SAFE_PARCEL(output.writeFloat, desiredSdrHdrRatio); return NO_ERROR; } @@ -321,6 +323,11 @@ status_t layer_state_t::read(const Parcel& input) SAFE_PARCEL(input.readParcelable, &trustedPresentationThresholds); SAFE_PARCEL(input.readParcelable, &trustedPresentationListener); + SAFE_PARCEL(input.readFloat, &tmpFloat); + currentSdrHdrRatio = tmpFloat; + SAFE_PARCEL(input.readFloat, &tmpFloat); + desiredSdrHdrRatio = tmpFloat; + return NO_ERROR; } @@ -568,6 +575,11 @@ void layer_state_t::merge(const layer_state_t& other) { what |= eDataspaceChanged; dataspace = other.dataspace; } + if (other.what & eExtendedRangeBrightnessChanged) { + what |= eExtendedRangeBrightnessChanged; + desiredSdrHdrRatio = other.desiredSdrHdrRatio; + currentSdrHdrRatio = other.currentSdrHdrRatio; + } if (other.what & eHdrMetadataChanged) { what |= eHdrMetadataChanged; hdrMetadata = other.hdrMetadata; @@ -714,6 +726,8 @@ uint64_t layer_state_t::diff(const layer_state_t& other) const { CHECK_DIFF(diff, eCropChanged, other, crop); if (other.what & eBufferChanged) diff |= eBufferChanged; CHECK_DIFF(diff, eDataspaceChanged, other, dataspace); + CHECK_DIFF2(diff, eExtendedRangeBrightnessChanged, other, currentSdrHdrRatio, + desiredSdrHdrRatio); CHECK_DIFF(diff, eHdrMetadataChanged, other, hdrMetadata); if (other.what & eSurfaceDamageRegionChanged && (!surfaceDamageRegion.hasSameRects(other.surfaceDamageRegion))) { diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 5bdeae8a1f..cf9828b2f8 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1673,6 +1673,21 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setDatas return *this; } +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setExtendedRangeBrightness( + const sp& sc, float currentBufferRatio, float desiredRatio) { + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } + s->what |= layer_state_t::eExtendedRangeBrightnessChanged; + s->currentSdrHdrRatio = currentBufferRatio; + s->desiredSdrHdrRatio = desiredRatio; + + registerSurfaceControlForCallback(sc); + return *this; +} + SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setHdrMetadata( const sp& sc, const HdrMetadata& hdrMetadata) { layer_state_t* s = getLayerState(sc); diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index 70c9daf42b..b8bee72cec 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -209,7 +209,8 @@ struct layer_state_t { eAutoRefreshChanged = 0x1000'00000000, eStretchChanged = 0x2000'00000000, eTrustedOverlayChanged = 0x4000'00000000, - eDropInputModeChanged = 0x8000'00000000 + eDropInputModeChanged = 0x8000'00000000, + eExtendedRangeBrightnessChanged = 0x10000'00000000 }; layer_state_t(); @@ -240,7 +241,8 @@ struct layer_state_t { layer_state_t::eBufferTransformChanged | layer_state_t::eDataspaceChanged | layer_state_t::eSidebandStreamChanged | layer_state_t::eSurfaceDamageRegionChanged | layer_state_t::eTransformToDisplayInverseChanged | - layer_state_t::eTransparentRegionChanged; + layer_state_t::eTransparentRegionChanged | + layer_state_t::eExtendedRangeBrightnessChanged; // Content updates. static constexpr uint64_t CONTENT_CHANGES = layer_state_t::BUFFER_CHANGES | @@ -385,6 +387,8 @@ struct layer_state_t { gui::DropInputMode dropInputMode; bool dimmingEnabled; + float currentSdrHdrRatio = 1.f; + float desiredSdrHdrRatio = 1.f; TrustedPresentationThresholds trustedPresentationThresholds; TrustedPresentationListener trustedPresentationListener; diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 439e06049b..c5f59c8e3d 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -559,6 +559,8 @@ public: Transaction& setBufferHasBarrier(const sp& sc, uint64_t barrierFrameNumber); Transaction& setDataspace(const sp& sc, ui::Dataspace dataspace); + Transaction& setExtendedRangeBrightness(const sp& sc, + float currentBufferRatio, float desiredRatio); Transaction& setHdrMetadata(const sp& sc, const HdrMetadata& hdrMetadata); Transaction& setSurfaceDamageRegion(const sp& sc, const Region& surfaceDamageRegion); diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h index ad98e93232..5bb249719e 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h @@ -209,6 +209,9 @@ struct LayerFECompositionState { // The dimming flag bool dimmingEnabled{true}; + float currentSdrHdrRatio = 1.f; + float desiredSdrHdrRatio = 1.f; + virtual ~LayerFECompositionState(); // Debugging diff --git a/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp index a405c4df88..531b65963d 100644 --- a/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp +++ b/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp @@ -121,6 +121,10 @@ void LayerFECompositionState::dump(std::string& out) const { dumpVal(out, "dataspace", toString(dataspace), dataspace); dumpVal(out, "hdr metadata types", hdrMetadata.validTypes); dumpVal(out, "dimming enabled", dimmingEnabled); + if (currentSdrHdrRatio > 1.01f || desiredSdrHdrRatio > 1.01f) { + dumpVal(out, "current sdr/hdr ratio", currentSdrHdrRatio); + dumpVal(out, "desired sdr/hdr ratio", desiredSdrHdrRatio); + } dumpVal(out, "colorTransform", colorTransform); out.append("\n"); diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp index 60a2c83194..6b69ce7941 100644 --- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp +++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp @@ -340,10 +340,17 @@ void OutputLayer::updateCompositionState( state.dimmingRatio = 1.f; state.whitePointNits = getOutput().getState().displayBrightnessNits; } else { - state.dimmingRatio = std::clamp(getOutput().getState().sdrWhitePointNits / - getOutput().getState().displayBrightnessNits, - 0.f, 1.f); - state.whitePointNits = getOutput().getState().sdrWhitePointNits; + float layerBrightnessNits = getOutput().getState().sdrWhitePointNits; + // RANGE_EXTENDED can "self-promote" to HDR, but is still rendered for a particular + // range that we may need to re-adjust to the current display conditions + if ((state.dataspace & HAL_DATASPACE_RANGE_MASK) == HAL_DATASPACE_RANGE_EXTENDED && + layerFEState->currentSdrHdrRatio > 1.01f) { + layerBrightnessNits *= layerFEState->currentSdrHdrRatio; + } + state.dimmingRatio = + std::clamp(layerBrightnessNits / getOutput().getState().displayBrightnessNits, 0.f, + 1.f); + state.whitePointNits = layerBrightnessNits; } // These are evaluated every frame as they can potentially change at any diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp index 40dffb9706..cc265916f1 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp +++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp @@ -667,6 +667,8 @@ void LayerSnapshotBuilder::updateSnapshot(LayerSnapshot& snapshot, const Args& a snapshot.sidebandStream = requested.sidebandStream; snapshot.transparentRegionHint = requested.transparentRegion; snapshot.color.rgb = requested.getColor().rgb; + snapshot.currentSdrHdrRatio = requested.currentSdrHdrRatio; + snapshot.desiredSdrHdrRatio = requested.desiredSdrHdrRatio; } if (snapshot.isHiddenByPolicyFromParent && !newSnapshot) { diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp index 39bf07abd2..b7fa4f0aa2 100644 --- a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp +++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp @@ -96,6 +96,8 @@ RequestedLayerState::RequestedLayerState(const LayerCreationArgs& args) layerStack = ui::DEFAULT_LAYER_STACK; transformToDisplayInverse = false; dataspace = ui::Dataspace::UNKNOWN; + desiredSdrHdrRatio = 1.f; + currentSdrHdrRatio = 1.f; dataspaceRequested = false; hdrMetadata.validTypes = 0; surfaceDamageRegion = Region::INVALID_REGION; diff --git a/services/surfaceflinger/HdrLayerInfoReporter.h b/services/surfaceflinger/HdrLayerInfoReporter.h index 4ada2b6372..9b70c164de 100644 --- a/services/surfaceflinger/HdrLayerInfoReporter.h +++ b/services/surfaceflinger/HdrLayerInfoReporter.h @@ -33,6 +33,17 @@ public: int32_t maxW = 0; int32_t maxH = 0; int32_t flags = 0; + // Counter-intuitively a value of "1" means "as much as you can give me" due to "1" being + // the default value for all layers, so any HDR layer with a value of 1.f means no + // reduced maximum has been requested + // TODO: Should the max desired ratio have a better meaning for HLG/PQ so this can be + // eliminated? If we assume an SDR white point of even just 100 nits for those content + // then HLG could have a meaningful max ratio of 10.f and PQ of 100.f instead of needing + // to treat 1.f as "uncapped" + // With peak display brightnesses exceeding 1,000 nits currently, HLG's request could + // actually be satisfied in some ambient conditions such that limiting that max for that + // content in theory makes sense + float maxDesiredSdrHdrRatio = 0.f; bool operator==(const HdrLayerInfo& other) const { return numberOfHdrLayers == other.numberOfHdrLayers && maxW == other.maxW && @@ -40,6 +51,20 @@ public: } bool operator!=(const HdrLayerInfo& other) const { return !(*this == other); } + + void mergeDesiredRatio(float update) { + if (maxDesiredSdrHdrRatio == 0.f) { + // If nothing is set, take the incoming value + maxDesiredSdrHdrRatio = update; + } else if (update == 1.f) { + // If the request is to "go to max", then take it regardless + maxDesiredSdrHdrRatio = 1.f; + } else if (maxDesiredSdrHdrRatio != 1.f) { + // If we're not currently asked to "go to max", then take the max + // of the incoming requests + maxDesiredSdrHdrRatio = std::max(maxDesiredSdrHdrRatio, update); + } + } }; HdrLayerInfoReporter() = default; diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 539f2fe353..953cdff237 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -622,6 +622,8 @@ void Layer::preparePerFrameCompositionState() { snapshot->surfaceDamage = surfaceDamageRegion; snapshot->hasProtectedContent = isProtected(); snapshot->dimmingEnabled = isDimmingEnabled(); + snapshot->currentSdrHdrRatio = getCurrentSdrHdrRatio(); + snapshot->desiredSdrHdrRatio = getDesiredSdrHdrRatio(); const bool usesRoundedCorners = hasRoundedCorners(); @@ -3041,6 +3043,17 @@ bool Layer::setDataspace(ui::Dataspace dataspace) { return true; } +bool Layer::setExtendedRangeBrightness(float currentBufferRatio, float desiredRatio) { + if (mDrawingState.currentSdrHdrRatio == currentBufferRatio && + mDrawingState.desiredSdrHdrRatio == desiredRatio) + return false; + mDrawingState.currentSdrHdrRatio = currentBufferRatio; + mDrawingState.desiredSdrHdrRatio = desiredRatio; + mDrawingState.modified = true; + setTransactionFlags(eTransactionNeeded); + return true; +} + bool Layer::setHdrMetadata(const HdrMetadata& hdrMetadata) { if (mDrawingState.hdrMetadata == hdrMetadata) return false; mDrawingState.hdrMetadata = hdrMetadata; @@ -3272,7 +3285,11 @@ void Layer::gatherBufferInfo() { auto lastDataspace = mBufferInfo.mDataspace; mBufferInfo.mDataspace = translateDataspace(mDrawingState.dataspace); if (lastDataspace != mBufferInfo.mDataspace) { - mFlinger->mSomeDataspaceChanged = true; + mFlinger->mHdrLayerInfoChanged = true; + } + if (mBufferInfo.mDesiredSdrHdrRatio != mDrawingState.desiredSdrHdrRatio) { + mBufferInfo.mDesiredSdrHdrRatio = mDrawingState.desiredSdrHdrRatio; + mFlinger->mHdrLayerInfoChanged = true; } mBufferInfo.mCrop = computeBufferCrop(mDrawingState); mBufferInfo.mScaleMode = NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW; @@ -3563,6 +3580,14 @@ bool Layer::simpleBufferUpdate(const layer_state_t& s) const { } } + if (s.what & layer_state_t::eExtendedRangeBrightnessChanged) { + if (mDrawingState.currentSdrHdrRatio != s.currentSdrHdrRatio || + mDrawingState.desiredSdrHdrRatio != s.desiredSdrHdrRatio) { + ALOGV("%s: false [eDimmingEnabledChanged changed]", __func__); + return false; + } + } + ALOGV("%s: true", __func__); return true; } diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 7631f5d963..3384e4af2d 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -223,6 +223,8 @@ public: gui::DropInputMode dropInputMode; bool autoRefresh = false; bool dimmingEnabled = true; + float currentSdrHdrRatio = 1.f; + float desiredSdrHdrRatio = 1.f; }; explicit Layer(const LayerCreationArgs& args); @@ -289,7 +291,9 @@ public: virtual mat4 getColorTransform() const; virtual bool hasColorTransform() const; virtual bool isColorSpaceAgnostic() const { return mDrawingState.colorSpaceAgnostic; } - virtual bool isDimmingEnabled() const { return getDrawingState().dimmingEnabled; }; + virtual bool isDimmingEnabled() const { return getDrawingState().dimmingEnabled; } + float getDesiredSdrHdrRatio() const { return getDrawingState().desiredSdrHdrRatio; } + float getCurrentSdrHdrRatio() const { return getDrawingState().currentSdrHdrRatio; } bool setTransform(uint32_t /*transform*/); bool setTransformToDisplayInverse(bool /*transformToDisplayInverse*/); @@ -298,6 +302,7 @@ public: nsecs_t /*desiredPresentTime*/, bool /*isAutoTimestamp*/, std::optional /* dequeueTime */, const FrameTimelineInfo& /*info*/); bool setDataspace(ui::Dataspace /*dataspace*/); + bool setExtendedRangeBrightness(float currentBufferRatio, float desiredRatio); bool setHdrMetadata(const HdrMetadata& /*hdrMetadata*/); bool setSurfaceDamageRegion(const Region& /*surfaceDamage*/); bool setApi(int32_t /*api*/); @@ -499,6 +504,7 @@ public: uint64_t mFrameNumber; bool mFrameLatencyNeeded{false}; + float mDesiredSdrHdrRatio = 1.f; }; BufferInfo mBufferInfo; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index cb3c94f5b0..546aceb74f 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2476,7 +2476,7 @@ void SurfaceFlinger::composite(TimePoint frameTime, VsyncId vsyncId) mLayerTracing.notify(mVisibleRegionsDirty, frameTime.ns(), vsyncId.value); } - mVisibleRegionsWereDirtyThisFrame = mVisibleRegionsDirty; // Cache value for use in post-comp + if (mVisibleRegionsDirty) mHdrLayerInfoChanged = true; mVisibleRegionsDirty = false; if (mCompositionEngine->needsAnotherUpdate()) { @@ -2504,21 +2504,32 @@ void SurfaceFlinger::updateLayerGeometry() { } bool SurfaceFlinger::isHdrLayer(Layer* layer) const { - // Treat all layers as non-HDR if: - // 1. They do not have a valid HDR dataspace. Currently we treat those as PQ or HLG. and - // 2. The layer is allowed to be dimmed. WindowManager may disable dimming in order to - // keep animations invoking SDR screenshots of HDR layers seamless. Treat such tagged - // layers as HDR so that DisplayManagerService does not try to change the screen brightness - if (!isHdrDataspace(layer->getDataSpace()) && layer->isDimmingEnabled()) { - return false; - } + // Even though the camera layer may be using an HDR transfer function or otherwise be "HDR" + // the device may need to avoid boosting the brightness as a result of these layers to + // reduce power consumption during camera recording if (mIgnoreHdrCameraLayers) { auto buffer = layer->getBuffer(); if (buffer && (buffer->getUsage() & GRALLOC_USAGE_HW_CAMERA_WRITE) != 0) { return false; } } - return true; + if (isHdrDataspace(layer->getDataSpace())) { + return true; + } + // If the layer is not allowed to be dimmed, treat it as HDR. WindowManager may disable + // dimming in order to keep animations invoking SDR screenshots of HDR layers seamless. + // Treat such tagged layers as HDR so that DisplayManagerService does not try to change + // the screen brightness + if (!layer->isDimmingEnabled()) { + return true; + } + // RANGE_EXTENDED layers may identify themselves as being "HDR" via a desired sdr/hdr ratio + if ((layer->getDataSpace() & (int32_t)Dataspace::RANGE_MASK) == + (int32_t)Dataspace::RANGE_EXTENDED && + layer->getDesiredSdrHdrRatio() > 1.01f) { + return true; + } + return false; } ui::Rotation SurfaceFlinger::getPhysicalDisplayOrientation(DisplayId displayId, @@ -2637,7 +2648,7 @@ void SurfaceFlinger::postComposition(nsecs_t callTime) { mAddingHDRLayerInfoListener = false; } - if (haveNewListeners || mSomeDataspaceChanged || mVisibleRegionsWereDirtyThisFrame) { + if (haveNewListeners || mHdrLayerInfoChanged) { for (auto& [compositionDisplay, listener] : hdrInfoListeners) { HdrLayerInfoReporter::HdrLayerInfo info; int32_t maxArea = 0; @@ -2649,6 +2660,7 @@ void SurfaceFlinger::postComposition(nsecs_t callTime) { const auto* outputLayer = compositionDisplay->getOutputLayerForLayer(layerFe); if (outputLayer) { + info.mergeDesiredRatio(layer->getDesiredSdrHdrRatio()); info.numberOfHdrLayers++; const auto displayFrame = outputLayer->getState().displayFrame; const int32_t area = displayFrame.width() * displayFrame.height(); @@ -2665,8 +2677,7 @@ void SurfaceFlinger::postComposition(nsecs_t callTime) { } } - mSomeDataspaceChanged = false; - mVisibleRegionsWereDirtyThisFrame = false; + mHdrLayerInfoChanged = false; mTransactionCallbackInvoker.addPresentFence(std::move(presentFence)); mTransactionCallbackInvoker.sendCallbacks(false /* onCommitOnly */); @@ -4492,9 +4503,6 @@ uint32_t SurfaceFlinger::setClientStateLocked(const FrameTimelineInfo& frameTime if (what & layer_state_t::eDataspaceChanged) { if (layer->setDataspace(s.dataspace)) flags |= eTraversalNeeded; } - if (what & layer_state_t::eHdrMetadataChanged) { - if (layer->setHdrMetadata(s.hdrMetadata)) flags |= eTraversalNeeded; - } if (what & layer_state_t::eSurfaceDamageRegionChanged) { if (layer->setSurfaceDamageRegion(s.surfaceDamageRegion)) flags |= eTraversalNeeded; } @@ -4568,6 +4576,14 @@ uint32_t SurfaceFlinger::setClientStateLocked(const FrameTimelineInfo& frameTime if (what & layer_state_t::eDimmingEnabledChanged) { if (layer->setDimmingEnabled(s.dimmingEnabled)) flags |= eTraversalNeeded; } + if (what & layer_state_t::eExtendedRangeBrightnessChanged) { + if (layer->setExtendedRangeBrightness(s.currentSdrHdrRatio, s.desiredSdrHdrRatio)) { + flags |= eTraversalNeeded; + } + } + if (what & layer_state_t::eHdrMetadataChanged) { + if (layer->setHdrMetadata(s.hdrMetadata)) flags |= eTraversalNeeded; + } if (what & layer_state_t::eTrustedOverlayChanged) { if (layer->setTrustedOverlay(s.isTrustedOverlay)) { flags |= eTraversalNeeded; diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 5e4015e728..c107d02c03 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -1140,9 +1140,8 @@ private: State mDrawingState{LayerVector::StateSet::Drawing}; bool mVisibleRegionsDirty = false; - // VisibleRegions dirty is already cleared by postComp, but we need to track it to prevent - // extra work in the HDR layer info listener. - bool mVisibleRegionsWereDirtyThisFrame = false; + bool mHdrLayerInfoChanged = false; + // Used to ensure we omit a callback when HDR layer info listener is newly added but the // scene hasn't changed bool mAddingHDRLayerInfoListener = false; @@ -1153,7 +1152,6 @@ private: // TODO: Also move visibleRegions over to a boolean system. bool mUpdateInputInfo = false; bool mSomeChildrenChanged; - bool mSomeDataspaceChanged = false; bool mForceTransactionDisplayChange = false; // Set if LayerMetadata has changed since the last LayerMetadata snapshot. @@ -1342,6 +1340,7 @@ private: std::unordered_map> mHdrLayerInfoListeners GUARDED_BY(mStateLock); + mutable std::mutex mCreatedLayersLock; struct LayerCreatedState { LayerCreatedState(const wp& layer, const wp parent, bool addToRoot) @@ -1497,6 +1496,7 @@ public: binder::Status removeHdrLayerInfoListener( const sp& displayToken, const sp& listener) override; + binder::Status notifyPowerBoost(int boostId) override; binder::Status setGlobalShadowSettings(const gui::Color& ambientColor, const gui::Color& spotColor, float lightPosY, -- cgit v1.2.3-59-g8ed1b From b39918f8a4360e32692aa6353a9b20416e3b7ad3 Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Fri, 27 Jan 2023 11:36:11 +0100 Subject: Adds a flush jank data layer state update type. A transaction can be sent to SurfaceFlinger with a layer state change of this type to wake up SurfaceFlinger and have it perform the layer state update logic, without updating anything, but triggering any side-effects, especially jank data processing. Bug: 235178314 Bug: 221393601 Bug: 225105422 Test: atest SurfaceFlinger_test Change-Id: Idf458c96cbe8f54224ebde6f517c08b9a5c48a06 --- libs/gui/LayerState.cpp | 3 +++ libs/gui/SurfaceComposerClient.cpp | 13 +++++++++++++ libs/gui/include/gui/LayerState.h | 2 +- libs/gui/include/gui/SurfaceComposerClient.h | 2 ++ services/surfaceflinger/SurfaceFlinger.cpp | 4 ++++ 5 files changed, 23 insertions(+), 1 deletion(-) (limited to 'libs/gui/LayerState.cpp') diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 8372363185..7772a65dae 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -684,6 +684,9 @@ void layer_state_t::merge(const layer_state_t& other) { what |= eDimmingEnabledChanged; dimmingEnabled = other.dimmingEnabled; } + if (other.what & eFlushJankData) { + what |= eFlushJankData; + } 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, diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 9092f5fe67..044fb4b080 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1180,6 +1180,19 @@ sp SurfaceComposerClient::Transaction::getDefaultApplyToken() { void SurfaceComposerClient::Transaction::setDefaultApplyToken(sp applyToken) { sApplyToken = applyToken; } + +status_t SurfaceComposerClient::Transaction::sendSurfaceFlushJankDataTransaction( + const sp& sc) { + Transaction t; + layer_state_t* s = t.getLayerState(sc); + if (!s) { + return BAD_INDEX; + } + + s->what |= layer_state_t::eFlushJankData; + t.registerSurfaceControlForCallback(sc); + return t.apply(/*sync=*/false, /* oneWay=*/true); +} // --------------------------------------------------------------------------- sp SurfaceComposerClient::createDisplay(const String8& displayName, bool secure, diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index b8bee72cec..03a2582589 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -170,7 +170,7 @@ struct layer_state_t { eTransparentRegionChanged = 0x00000020, eFlagsChanged = 0x00000040, eLayerStackChanged = 0x00000080, - /* unused = 0x00000100, */ + eFlushJankData = 0x00000100, /* unused = 0x00000200, */ eDimmingEnabledChanged = 0x00000400, eShadowRadiusChanged = 0x00000800, diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 45f4dbe2be..8ae2b3ccc0 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -742,6 +742,8 @@ public: static sp getDefaultApplyToken(); static void setDefaultApplyToken(sp applyToken); + + static status_t sendSurfaceFlushJankDataTransaction(const sp& sc); }; status_t clearLayerFrameStats(const sp& token) const; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index a0c3eb0e26..2f5f93c16b 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -4843,6 +4843,10 @@ uint32_t SurfaceFlinger::setClientStateLocked(const FrameTimelineInfo& frameTime s.trustedPresentationListener); } + if (what & layer_state_t::eFlushJankData) { + // Do nothing. Processing the transaction completed listeners currently cause the flush. + } + if (layer->setTransactionCompletedListeners(callbackHandles, layer->willPresentCurrentTransaction())) { flags |= eTraversalNeeded; -- cgit v1.2.3-59-g8ed1b From eb489f69db265f6cb1aab63130750d0c12c99d94 Mon Sep 17 00:00:00 2001 From: liulijun Date: Mon, 17 Oct 2022 22:02:14 +0800 Subject: Add producerId so we know when the BBQ producer has been changed. If BBQ producer changes but the SC remains the same, the frame numbers for the SC will get reset. This causes issues if there's a barrier layer set because the barrier is waiting for a particular frame number before applying the transaction. Since the frame numbers have been reset, the barrier will be greater than the incoming frame numbers. The change adds a producerId to the buffer being sent so it can check if the producerId is older than what's currently set on the Layer. If there's a barriers set from the old producer, the buffer can be released and not applied and will stop SF from waiting indefinitely. Bug: 251971691 Test: Builds, hard to repro Signed-off-by: Liu Lijun Change-Id: If37171de4693a73f36f8de43e29c129b352eb55f --- libs/gui/BLASTBufferQueue.cpp | 14 ++++---- libs/gui/LayerState.cpp | 2 ++ libs/gui/SurfaceComposerClient.cpp | 3 +- libs/gui/include/gui/BLASTBufferQueue.h | 5 +++ libs/gui/include/gui/LayerState.h | 1 + libs/gui/include/gui/SurfaceComposerClient.h | 2 +- .../surfaceflinger/FrontEnd/TransactionHandler.h | 2 +- services/surfaceflinger/Layer.cpp | 18 ++++------ services/surfaceflinger/Layer.h | 10 ++++++ services/surfaceflinger/SurfaceFlinger.cpp | 40 +++++++++++++++------- services/surfaceflinger/TransactionState.h | 22 +++++++++--- .../tests/ReleaseBufferCallback_test.cpp | 26 +++++++------- 12 files changed, 95 insertions(+), 50 deletions(-) (limited to 'libs/gui/LayerState.cpp') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index 66c0041965..9d82c143f5 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -20,6 +20,7 @@ #define ATRACE_TAG ATRACE_TAG_GRAPHICS //#define LOG_NDEBUG 0 +#include #include #include #include @@ -157,11 +158,11 @@ BLASTBufferQueue::BLASTBufferQueue(const std::string& name, bool updateDestinati GraphicBuffer::USAGE_HW_COMPOSER | GraphicBuffer::USAGE_HW_TEXTURE, 1, false, this); - static int32_t id = 0; - mName = name + "#" + std::to_string(id); - auto consumerName = mName + "(BLAST Consumer)" + std::to_string(id); - mQueuedBufferTrace = "QueuedBuffer - " + mName + "BLAST#" + std::to_string(id); - id++; + static std::atomic nextId = 0; + mProducerId = nextId++; + mName = name + "#" + std::to_string(mProducerId); + auto consumerName = mName + "(BLAST Consumer)" + std::to_string(mProducerId); + mQueuedBufferTrace = "QueuedBuffer - " + mName + "BLAST#" + std::to_string(mProducerId); mBufferItemConsumer->setName(String8(consumerName.c_str())); mBufferItemConsumer->setFrameAvailableListener(this); @@ -572,7 +573,8 @@ status_t BLASTBufferQueue::acquireNextBufferLocked( std::bind(releaseBufferCallbackThunk, wp(this) /* callbackContext */, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3); sp fence = bufferItem.mFence ? new Fence(bufferItem.mFence->dup()) : Fence::NO_FENCE; - t->setBuffer(mSurfaceControl, buffer, fence, bufferItem.mFrameNumber, releaseBufferCallback); + t->setBuffer(mSurfaceControl, buffer, fence, bufferItem.mFrameNumber, mProducerId, + releaseBufferCallback); t->setDataspace(mSurfaceControl, static_cast(bufferItem.mDataSpace)); t->setHdrMetadata(mSurfaceControl, bufferItem.mHdrMetadata); t->setSurfaceDamageRegion(mSurfaceControl, bufferItem.mSurfaceDamage); diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 7772a65dae..a6276e500c 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -984,6 +984,7 @@ status_t BufferData::writeToParcel(Parcel* output) const { SAFE_PARCEL(output->writeUint64, cachedBuffer.id); SAFE_PARCEL(output->writeBool, hasBarrier); SAFE_PARCEL(output->writeUint64, barrierFrameNumber); + SAFE_PARCEL(output->writeUint32, producerId); return NO_ERROR; } @@ -1022,6 +1023,7 @@ status_t BufferData::readFromParcel(const Parcel* input) { SAFE_PARCEL(input->readBool, &hasBarrier); SAFE_PARCEL(input->readUint64, &barrierFrameNumber); + SAFE_PARCEL(input->readUint32, &producerId); return NO_ERROR; } diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index a34593825a..5088604396 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1632,7 +1632,7 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBuffe SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBuffer( const sp& sc, const sp& buffer, const std::optional>& fence, const std::optional& optFrameNumber, - ReleaseBufferCallback callback) { + uint32_t producerId, ReleaseBufferCallback callback) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; @@ -1651,6 +1651,7 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBuffe bufferData->buffer = buffer; uint64_t frameNumber = sc->resolveFrameNumber(optFrameNumber); bufferData->frameNumber = frameNumber; + bufferData->producerId = producerId; bufferData->flags |= BufferData::BufferDataChange::frameNumberChanged; if (fence) { bufferData->acquireFence = *fence; diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index 8d07162f1b..b9e06473bf 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -162,6 +162,11 @@ private: int32_t mNumFrameAvailable GUARDED_BY(mMutex) = 0; int32_t mNumAcquired GUARDED_BY(mMutex) = 0; + // A value used to identify if a producer has been changed for the same SurfaceControl. + // This is needed to know when the frame number has been reset to make sure we don't + // latch stale buffers and that we don't wait on barriers from an old producer. + uint32_t mProducerId = 0; + // Keep a reference to the submitted buffers so we can release when surfaceflinger drops the // buffer or the buffer has been presented and a new buffer is ready to be presented. std::unordered_map mSubmitted diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index 03a2582589..ddaf473855 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -111,6 +111,7 @@ public: uint64_t frameNumber = 0; bool hasBarrier = false; uint64_t barrierFrameNumber = 0; + uint32_t producerId = 0; // Listens to when the buffer is safe to be released. This is used for blast // layers only. The callback includes a release fence as well as the graphic diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 809ea5a30f..ffd5af100d 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -536,7 +536,7 @@ public: Transaction& setBuffer(const sp& sc, const sp& buffer, const std::optional>& fence = std::nullopt, const std::optional& frameNumber = std::nullopt, - ReleaseBufferCallback callback = nullptr); + uint32_t producerId = 0, ReleaseBufferCallback callback = nullptr); std::shared_ptr getAndClearBuffer(const sp& sc); /** diff --git a/services/surfaceflinger/FrontEnd/TransactionHandler.h b/services/surfaceflinger/FrontEnd/TransactionHandler.h index a06b870549..7fc825eba3 100644 --- a/services/surfaceflinger/FrontEnd/TransactionHandler.h +++ b/services/surfaceflinger/FrontEnd/TransactionHandler.h @@ -34,7 +34,7 @@ namespace surfaceflinger::frontend { class TransactionHandler { public: struct TransactionFlushState { - const TransactionState* transaction; + TransactionState* transaction; bool firstTransaction = true; nsecs_t queueProcessTime = 0; // Layer handles that have transactions with buffers that are ready to be applied. diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 66c2fb658f..8c484f0039 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -228,9 +228,7 @@ Layer::~Layer() { if (mBufferInfo.mBuffer != nullptr) { callReleaseBufferCallback(mDrawingState.releaseBufferListener, mBufferInfo.mBuffer->getBuffer(), mBufferInfo.mFrameNumber, - mBufferInfo.mFence, - mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate( - mOwnerUid)); + mBufferInfo.mFence); } if (!isClone()) { // The original layer and the clone layer share the same texture. Therefore, only one of @@ -2732,12 +2730,13 @@ void Layer::cloneDrawingState(const Layer* from) { void Layer::callReleaseBufferCallback(const sp& listener, const sp& buffer, uint64_t framenumber, - const sp& releaseFence, - uint32_t currentMaxAcquiredBufferCount) { + const sp& releaseFence) { if (!listener) { return; } ATRACE_FORMAT_INSTANT("callReleaseBufferCallback %s - %" PRIu64, getDebugName(), framenumber); + uint32_t currentMaxAcquiredBufferCount = + mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate(mOwnerUid); listener->onReleaseBuffer({buffer->getId(), framenumber}, releaseFence ? releaseFence : Fence::NO_FENCE, currentMaxAcquiredBufferCount); @@ -2988,9 +2987,7 @@ bool Layer::setBuffer(std::shared_ptr& buffer, // call any release buffer callbacks if set. callReleaseBufferCallback(mDrawingState.releaseBufferListener, mDrawingState.buffer->getBuffer(), mDrawingState.frameNumber, - mDrawingState.acquireFence, - mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate( - mOwnerUid)); + mDrawingState.acquireFence); decrementPendingBufferCount(); if (mDrawingState.bufferSurfaceFrameTX != nullptr && mDrawingState.bufferSurfaceFrameTX->getPresentState() != PresentState::Presented) { @@ -3000,13 +2997,12 @@ bool Layer::setBuffer(std::shared_ptr& buffer, } else if (EARLY_RELEASE_ENABLED && mLastClientCompositionFence != nullptr) { callReleaseBufferCallback(mDrawingState.releaseBufferListener, mDrawingState.buffer->getBuffer(), mDrawingState.frameNumber, - mLastClientCompositionFence, - mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate( - mOwnerUid)); + mLastClientCompositionFence); mLastClientCompositionFence = nullptr; } } + mDrawingState.producerId = bufferData.producerId; mDrawingState.frameNumber = frameNumber; mDrawingState.releaseBufferListener = bufferData.releaseBufferListener; mDrawingState.buffer = std::move(buffer); diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 07c01d8e17..bf8cc7e36b 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -141,6 +141,8 @@ public: uint64_t frameNumber; ui::Transform transform; + + uint32_t producerId = 0; uint32_t bufferTransform; bool transformToDisplayInverse; Region transparentRegionHint; @@ -838,6 +840,10 @@ public: std::unordered_set& visited); bool willPresentCurrentTransaction() const; + void callReleaseBufferCallback(const sp& listener, + const sp& buffer, uint64_t framenumber, + const sp& releaseFence); + protected: // For unit tests friend class TestableSurfaceFlinger; @@ -1047,6 +1053,10 @@ private: const sp& releaseFence, uint32_t currentMaxAcquiredBufferCount); + // Returns true if the transformed buffer size does not match the layer size and we need + // to apply filtering. + bool bufferNeedsFiltering() const; + // Returns true if there is a valid color to fill. bool fillsColor() const; // Returns true if this layer has a blur value. diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 68ab776400..e74656e55c 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -4058,16 +4058,30 @@ TransactionHandler::TransactionReadiness SurfaceFlinger::transactionReadyBufferC sp layer = LayerHandle::getLayer(s.surface); const auto& transaction = *flushState.transaction; // check for barrier frames - if (s.bufferData->hasBarrier && - ((layer->getDrawingState().frameNumber) < s.bufferData->barrierFrameNumber)) { - const bool willApplyBarrierFrame = - flushState.bufferLayersReadyToPresent.contains(s.surface.get()) && - (flushState.bufferLayersReadyToPresent.get(s.surface.get()) >= - s.bufferData->barrierFrameNumber); - if (!willApplyBarrierFrame) { - ATRACE_NAME("NotReadyBarrier"); - ready = TransactionReadiness::NotReadyBarrier; - return false; + if (s.bufferData->hasBarrier) { + // The current producerId is already a newer producer than the buffer that has a + // barrier. This means the incoming buffer is older and we can release it here. We + // don't wait on the barrier since we know that's stale information. + if (layer->getDrawingState().producerId > s.bufferData->producerId) { + layer->callReleaseBufferCallback(s.bufferData->releaseBufferListener, + s.bufferData->buffer, s.bufferData->frameNumber, + s.bufferData->acquireFence); + // Delete the entire state at this point and not just release the buffer because + // everything associated with the Layer in this Transaction is now out of date. + ATRACE_NAME("DeleteStaleBuffer"); + return TraverseBuffersReturnValues::DELETE_AND_CONTINUE_TRAVERSAL; + } + + if (layer->getDrawingState().frameNumber < s.bufferData->barrierFrameNumber) { + const bool willApplyBarrierFrame = + flushState.bufferLayersReadyToPresent.contains(s.surface.get()) && + ((flushState.bufferLayersReadyToPresent.get(s.surface.get()) >= + s.bufferData->barrierFrameNumber)); + if (!willApplyBarrierFrame) { + ATRACE_NAME("NotReadyBarrier"); + ready = TransactionReadiness::NotReadyBarrier; + return TraverseBuffersReturnValues::STOP_TRAVERSAL; + } } } @@ -4078,7 +4092,7 @@ TransactionHandler::TransactionReadiness SurfaceFlinger::transactionReadyBufferC if (layer->backpressureEnabled() && hasPendingBuffer && transaction.isAutoTimestamp) { ATRACE_NAME("hasPendingBuffer"); ready = TransactionReadiness::NotReady; - return false; + return TraverseBuffersReturnValues::STOP_TRAVERSAL; } // check fence status @@ -4105,14 +4119,14 @@ TransactionHandler::TransactionReadiness SurfaceFlinger::transactionReadyBufferC "Buffer processing hung up due to stuck " "fence. Indicates GPU hang"); } - return false; + return TraverseBuffersReturnValues::STOP_TRAVERSAL; } ready = enableLatchUnsignaledConfig == LatchUnsignaledConfig::AutoSingleLayer ? TransactionReadiness::ReadyUnsignaledSingle : TransactionReadiness::ReadyUnsignaled; } - return true; + return TraverseBuffersReturnValues::CONTINUE_TRAVERSAL; }); ATRACE_INT("TransactionReadiness", static_cast(ready)); return ready; diff --git a/services/surfaceflinger/TransactionState.h b/services/surfaceflinger/TransactionState.h index 5025c4935c..6c5a8b213d 100644 --- a/services/surfaceflinger/TransactionState.h +++ b/services/surfaceflinger/TransactionState.h @@ -27,6 +27,12 @@ namespace android { +enum TraverseBuffersReturnValues { + CONTINUE_TRAVERSAL, + STOP_TRAVERSAL, + DELETE_AND_CONTINUE_TRAVERSAL, +}; + // Extends the client side composer state by resolving buffer. class ResolvedComposerState : public ComposerState { public: @@ -75,12 +81,18 @@ struct TransactionState { } template - void traverseStatesWithBuffersWhileTrue(Visitor&& visitor) const { - for (const auto& state : states) { - if (state.state.hasBufferChanges() && state.state.hasValidBuffer() && - state.state.surface) { - if (!visitor(state.state)) return; + void traverseStatesWithBuffersWhileTrue(Visitor&& visitor) { + for (auto state = states.begin(); state != states.end();) { + if (state->state.hasBufferChanges() && state->state.hasValidBuffer() && + state->state.surface) { + int result = visitor(state->state); + if (result == STOP_TRAVERSAL) return; + if (result == DELETE_AND_CONTINUE_TRAVERSAL) { + state = states.erase(state); + continue; + } } + state++; } } diff --git a/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp b/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp index 16076eaac9..c23fb9bd23 100644 --- a/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp +++ b/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp @@ -85,7 +85,8 @@ public: sp fence, CallbackHelper& callback, const ReleaseCallbackId& id, ReleaseBufferCallbackHelper& releaseCallback) { Transaction t; - t.setBuffer(layer, buffer, fence, id.framenumber, releaseCallback.getCallback()); + t.setBuffer(layer, buffer, fence, id.framenumber, 0 /* producerId */, + releaseCallback.getCallback()); t.addTransactionCompletedCallback(callback.function, callback.getContext()); t.apply(); } @@ -301,7 +302,7 @@ TEST_F(ReleaseBufferCallbackTest, DISABLED_FrameDropping) { Transaction t; t.setBuffer(layer, firstBuffer, std::nullopt, firstBufferCallbackId.framenumber, - releaseCallback->getCallback()); + 0 /* producerId */, releaseCallback->getCallback()); t.addTransactionCompletedCallback(transactionCallback.function, transactionCallback.getContext()); t.setDesiredPresentTime(time); @@ -317,7 +318,7 @@ TEST_F(ReleaseBufferCallbackTest, DISABLED_FrameDropping) { sp secondBuffer = getBuffer(); ReleaseCallbackId secondBufferCallbackId(secondBuffer->getId(), generateFrameNumber()); t.setBuffer(layer, secondBuffer, std::nullopt, secondBufferCallbackId.framenumber, - releaseCallback->getCallback()); + 0 /* producerId */, releaseCallback->getCallback()); t.addTransactionCompletedCallback(transactionCallback.function, transactionCallback.getContext()); t.setDesiredPresentTime(time); @@ -362,7 +363,7 @@ TEST_F(ReleaseBufferCallbackTest, DISABLED_Merge_Different_Processes) { Transaction transaction1; transaction1.setBuffer(layer, secondBuffer, std::nullopt, secondBufferCallbackId.framenumber, - releaseCallback->getCallback()); + 0 /* producerId */, releaseCallback->getCallback()); transaction1.addTransactionCompletedCallback(callback1.function, callback1.getContext()); // Set a different TransactionCompletedListener to mimic a second process @@ -397,14 +398,14 @@ TEST_F(ReleaseBufferCallbackTest, DISABLED_SetBuffer_OverwriteBuffers) { // Create transaction with a buffer. Transaction transaction; transaction.setBuffer(layer, firstBuffer, std::nullopt, firstBufferCallbackId.framenumber, - releaseCallback->getCallback()); + 0 /* producerId */, releaseCallback->getCallback()); sp secondBuffer = getBuffer(); ReleaseCallbackId secondBufferCallbackId(secondBuffer->getId(), generateFrameNumber()); // Call setBuffer on the same transaction with a different buffer. transaction.setBuffer(layer, secondBuffer, std::nullopt, secondBufferCallbackId.framenumber, - releaseCallback->getCallback()); + 0 /* producerId */, releaseCallback->getCallback()); ASSERT_NO_FATAL_FAILURE(waitForReleaseBufferCallback(*releaseCallback, firstBufferCallbackId)); } @@ -419,7 +420,7 @@ TEST_F(ReleaseBufferCallbackTest, DISABLED_Merge_Transactions_OverwriteBuffers) // Create transaction with a buffer. Transaction transaction1; transaction1.setBuffer(layer, firstBuffer, std::nullopt, firstBufferCallbackId.framenumber, - releaseCallback->getCallback()); + 0 /* producerId */, releaseCallback->getCallback()); sp secondBuffer = getBuffer(); ReleaseCallbackId secondBufferCallbackId(secondBuffer->getId(), generateFrameNumber()); @@ -427,7 +428,7 @@ TEST_F(ReleaseBufferCallbackTest, DISABLED_Merge_Transactions_OverwriteBuffers) // Create a second transaction with a new buffer for the same layer. Transaction transaction2; transaction2.setBuffer(layer, secondBuffer, std::nullopt, secondBufferCallbackId.framenumber, - releaseCallback->getCallback()); + 0 /* producerId */, releaseCallback->getCallback()); // merge transaction1 into transaction2 so ensure we get a proper buffer release callback. transaction1.merge(std::move(transaction2)); @@ -450,7 +451,7 @@ TEST_F(ReleaseBufferCallbackTest, DISABLED_MergeBuffers_Different_Processes) { Transaction transaction1; transaction1.setBuffer(layer, firstBuffer, std::nullopt, firstBufferCallbackId.framenumber, - releaseCallback->getCallback()); + 0 /* producerId */, releaseCallback->getCallback()); // Sent a second buffer to allow the first buffer to get released. sp secondBuffer = getBuffer(); @@ -458,7 +459,7 @@ TEST_F(ReleaseBufferCallbackTest, DISABLED_MergeBuffers_Different_Processes) { Transaction transaction2; transaction2.setBuffer(layer, secondBuffer, std::nullopt, secondBufferCallbackId.framenumber, - releaseCallback->getCallback()); + 0 /* producerId */, releaseCallback->getCallback()); // Set a different TransactionCompletedListener to mimic a second process TransactionCompletedListener::setInstance(secondCompletedListener); @@ -479,10 +480,11 @@ TEST_F(ReleaseBufferCallbackTest, SetBuffer_OverwriteBuffersWithNull) { // Create transaction with a buffer. Transaction transaction; transaction.setBuffer(layer, firstBuffer, std::nullopt, firstBufferCallbackId.framenumber, - releaseCallback->getCallback()); + 0 /* producerId */, releaseCallback->getCallback()); // Call setBuffer on the same transaction with a null buffer. - transaction.setBuffer(layer, nullptr, std::nullopt, 0, releaseCallback->getCallback()); + transaction.setBuffer(layer, nullptr, std::nullopt, 0, 0 /* producerId */, + releaseCallback->getCallback()); ASSERT_NO_FATAL_FAILURE(waitForReleaseBufferCallback(*releaseCallback, firstBufferCallbackId)); } -- cgit v1.2.3-59-g8ed1b From f4af03ed9592dae0f2355dfff92c3c75c1b980d4 Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Sat, 11 Feb 2023 00:25:24 +0000 Subject: Add CachingHint into SurfaceFlinger Some system layers may need to be excluded from surfaceflinger caching for a variety of reasons, including power or image quality considerations. This provides a mechanism for those system layers to never be cached on the GPU. Bug: 259311918 Test: libcompositionengine_test Test: run test app and inspect planner state Change-Id: I35418ad5a41cb2546e3b27b0af290bf3c31a0180 --- libs/gui/LayerState.cpp | 10 +++++ libs/gui/SurfaceComposerClient.cpp | 14 +++++++ libs/gui/aidl/android/gui/CachingHint.aidl | 30 +++++++++++++ libs/gui/include/gui/ISurfaceComposer.h | 1 + libs/gui/include/gui/LayerState.h | 7 +++- libs/gui/include/gui/SurfaceComposerClient.h | 1 + .../compositionengine/LayerFECompositionState.h | 2 + .../compositionengine/impl/planner/CachedSet.h | 3 ++ .../compositionengine/impl/planner/LayerState.h | 19 ++++++--- .../src/LayerFECompositionState.cpp | 1 + .../CompositionEngine/src/planner/CachedSet.cpp | 12 ++++++ .../CompositionEngine/src/planner/Flattener.cpp | 4 +- .../tests/planner/CachedSetTest.cpp | 14 +++++++ .../tests/planner/FlattenerTest.cpp | 49 ++++++++++++++++++++++ .../tests/planner/LayerStateTest.cpp | 39 +++++++++++++++++ .../FrontEnd/LayerSnapshotBuilder.cpp | 1 + .../FrontEnd/RequestedLayerState.cpp | 1 + services/surfaceflinger/Layer.cpp | 17 +++++++- services/surfaceflinger/Layer.h | 3 ++ services/surfaceflinger/LayerFE.h | 1 + services/surfaceflinger/SurfaceFlinger.cpp | 5 +++ 21 files changed, 225 insertions(+), 9 deletions(-) create mode 100644 libs/gui/aidl/android/gui/CachingHint.aidl (limited to 'libs/gui/LayerState.cpp') diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index a6276e500c..f6bba16899 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -189,6 +189,7 @@ status_t layer_state_t::write(Parcel& output) const SAFE_PARCEL(output.writeParcelable, trustedPresentationListener); SAFE_PARCEL(output.writeFloat, currentSdrHdrRatio); SAFE_PARCEL(output.writeFloat, desiredSdrHdrRatio); + SAFE_PARCEL(output.writeInt32, static_cast(cachingHint)) return NO_ERROR; } @@ -328,6 +329,10 @@ status_t layer_state_t::read(const Parcel& input) SAFE_PARCEL(input.readFloat, &tmpFloat); desiredSdrHdrRatio = tmpFloat; + int32_t tmpInt32; + SAFE_PARCEL(input.readInt32, &tmpInt32); + cachingHint = static_cast(tmpInt32); + return NO_ERROR; } @@ -580,6 +585,10 @@ void layer_state_t::merge(const layer_state_t& other) { desiredSdrHdrRatio = other.desiredSdrHdrRatio; currentSdrHdrRatio = other.currentSdrHdrRatio; } + if (other.what & eCachingHintChanged) { + what |= eCachingHintChanged; + cachingHint = other.cachingHint; + } if (other.what & eHdrMetadataChanged) { what |= eHdrMetadataChanged; hdrMetadata = other.hdrMetadata; @@ -731,6 +740,7 @@ uint64_t layer_state_t::diff(const layer_state_t& other) const { CHECK_DIFF(diff, eDataspaceChanged, other, dataspace); CHECK_DIFF2(diff, eExtendedRangeBrightnessChanged, other, currentSdrHdrRatio, desiredSdrHdrRatio); + CHECK_DIFF(diff, eCachingHintChanged, other, cachingHint); CHECK_DIFF(diff, eHdrMetadataChanged, other, hdrMetadata); if (other.what & eSurfaceDamageRegionChanged && (!surfaceDamageRegion.hasSameRects(other.surfaceDamageRegion))) { diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index c5089173bd..001d475823 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1729,6 +1729,20 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setExten return *this; } +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setCachingHint( + const sp& sc, gui::CachingHint cachingHint) { + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } + s->what |= layer_state_t::eCachingHintChanged; + s->cachingHint = cachingHint; + + registerSurfaceControlForCallback(sc); + return *this; +} + SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setHdrMetadata( const sp& sc, const HdrMetadata& hdrMetadata) { layer_state_t* s = getLayerState(sc); diff --git a/libs/gui/aidl/android/gui/CachingHint.aidl b/libs/gui/aidl/android/gui/CachingHint.aidl new file mode 100644 index 0000000000..b35c79547f --- /dev/null +++ b/libs/gui/aidl/android/gui/CachingHint.aidl @@ -0,0 +1,30 @@ +/* + * Copyright 2022 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; + +/* + * Hint for configuring caching behavior for a layer + * @hide + */ +@Backing(type="int") +enum CachingHint { + // Caching is disabled. A layer may explicitly disable caching for + // improving image quality for some scenes. + Disabled = 0, + // Caching is enabled. A layer is cacheable by default. + Enabled = 1 +} diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index ae56f9fdb5..1e67225a4e 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -16,6 +16,7 @@ #pragma once +#include #include #include #include diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index ddaf473855..da144bd191 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -172,7 +172,7 @@ struct layer_state_t { eFlagsChanged = 0x00000040, eLayerStackChanged = 0x00000080, eFlushJankData = 0x00000100, - /* unused = 0x00000200, */ + eCachingHintChanged = 0x00000200, eDimmingEnabledChanged = 0x00000400, eShadowRadiusChanged = 0x00000800, eRenderBorderChanged = 0x00001000, @@ -211,7 +211,8 @@ struct layer_state_t { eStretchChanged = 0x2000'00000000, eTrustedOverlayChanged = 0x4000'00000000, eDropInputModeChanged = 0x8000'00000000, - eExtendedRangeBrightnessChanged = 0x10000'00000000 + eExtendedRangeBrightnessChanged = 0x10000'00000000, + }; layer_state_t(); @@ -391,6 +392,8 @@ struct layer_state_t { float currentSdrHdrRatio = 1.f; float desiredSdrHdrRatio = 1.f; + gui::CachingHint cachingHint = gui::CachingHint::Enabled; + TrustedPresentationThresholds trustedPresentationThresholds; TrustedPresentationListener trustedPresentationListener; }; diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 44e78ec0c4..d431b4381a 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -566,6 +566,7 @@ public: Transaction& setDataspace(const sp& sc, ui::Dataspace dataspace); Transaction& setExtendedRangeBrightness(const sp& sc, float currentBufferRatio, float desiredRatio); + Transaction& setCachingHint(const sp& sc, gui::CachingHint cachingHint); Transaction& setHdrMetadata(const sp& sc, const HdrMetadata& hdrMetadata); Transaction& setSurfaceDamageRegion(const sp& sc, const Region& surfaceDamageRegion); diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h index 32684fc3b7..0b4d20c660 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h @@ -18,6 +18,7 @@ #include +#include #include #include #include @@ -213,6 +214,7 @@ struct LayerFECompositionState { float desiredSdrHdrRatio = 1.f; bool isInternalDisplayOverlay = false; + gui::CachingHint cachingHint = gui::CachingHint::Enabled; virtual ~LayerFECompositionState(); diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h index 24a7744542..d26ca9dd00 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h @@ -149,6 +149,9 @@ public: bool hasSolidColorLayers() const; + // True if any layer in this cached set has CachingHint::Disabled + bool cachingHintExcludesLayers() const; + private: const NonBufferHash mFingerprint; std::chrono::steady_clock::time_point mLastUpdate = std::chrono::steady_clock::now(); diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h index e309442220..d5c488e40e 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h @@ -73,6 +73,7 @@ enum class LayerStateField : uint32_t { BackgroundBlurRadius = 1u << 17, BlurRegions = 1u << 18, HasProtectedContent = 1u << 19, + CachingHint = 1u << 20, }; // clang-format on @@ -250,6 +251,8 @@ public: bool isProtected() const { return mIsProtected.get(); } + gui::CachingHint getCachingHint() const { return mCachingHint.get(); } + bool hasSolidColorCompositionType() const { return getOutputLayer()->getLayerFE().getCompositionState()->compositionType == aidl::android::hardware::graphics::composer3::Composition::SOLID_COLOR; @@ -487,7 +490,15 @@ private: return layer->getLayerFE().getCompositionState()->hasProtectedContent; }}; - static const constexpr size_t kNumNonUniqueFields = 18; + OutputLayerState + mCachingHint{[](auto layer) { + return layer->getLayerFE().getCompositionState()->cachingHint; + }, + [](const gui::CachingHint& cachingHint) { + return std::vector{toString(cachingHint)}; + }}; + + static const constexpr size_t kNumNonUniqueFields = 19; std::array getNonUniqueFields() { std::array constFields = @@ -501,13 +512,11 @@ private: } std::array getNonUniqueFields() const { - return { - &mDisplayFrame, &mSourceCrop, &mBufferTransform, &mBlendMode, + return {&mDisplayFrame, &mSourceCrop, &mBufferTransform, &mBlendMode, &mAlpha, &mLayerMetadata, &mVisibleRegion, &mOutputDataspace, &mPixelFormat, &mColorTransform, &mCompositionType, &mSidebandStream, &mBuffer, &mSolidColor, &mBackgroundBlurRadius, &mBlurRegions, - &mFrameNumber, &mIsProtected, - }; + &mFrameNumber, &mIsProtected, &mCachingHint}; } }; diff --git a/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp index 531b65963d..615d04b460 100644 --- a/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp +++ b/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp @@ -126,6 +126,7 @@ void LayerFECompositionState::dump(std::string& out) const { dumpVal(out, "desired sdr/hdr ratio", desiredSdrHdrRatio); } dumpVal(out, "colorTransform", colorTransform); + dumpVal(out, "caching hint", toString(cachingHint)); out.append("\n"); } diff --git a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp index ed9a88d3c4..a00ce57e29 100644 --- a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp +++ b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp @@ -393,6 +393,18 @@ bool CachedSet::hasSolidColorLayers() const { }); } +bool CachedSet::cachingHintExcludesLayers() const { + const bool shouldExcludeLayers = + std::any_of(mLayers.cbegin(), mLayers.cend(), [](const Layer& layer) { + return layer.getState()->getCachingHint() == gui::CachingHint::Disabled; + }); + + LOG_ALWAYS_FATAL_IF(shouldExcludeLayers && getLayerCount() > 1, + "CachedSet is invalid: should be excluded but contains %zu layers", + getLayerCount()); + return shouldExcludeLayers; +} + void CachedSet::dump(std::string& result) const { const auto now = std::chrono::steady_clock::now(); diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp index 9175dd01a1..13b6307aea 100644 --- a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp +++ b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp @@ -413,6 +413,7 @@ std::vector Flattener::findCandidateRuns(time_point now) const { for (auto currentSet = mLayers.cbegin(); currentSet != mLayers.cend(); ++currentSet) { bool layerIsInactive = now - currentSet->getLastUpdate() > mTunables.mActiveLayerTimeout; const bool layerHasBlur = currentSet->hasBlurBehind(); + const bool layerDeniedFromCaching = currentSet->cachingHintExcludesLayers(); // Layers should also be considered inactive whenever their framerate is lower than 1fps. if (!layerIsInactive && currentSet->getLayerCount() == kNumLayersFpsConsideration) { @@ -424,7 +425,8 @@ std::vector Flattener::findCandidateRuns(time_point now) const { } } - if (layerIsInactive && (firstLayer || runHasFirstLayer || !layerHasBlur) && + if (!layerDeniedFromCaching && layerIsInactive && + (firstLayer || runHasFirstLayer || !layerHasBlur) && !currentSet->hasUnsupportedDataspace()) { if (isPartOfRun) { builder.increment(); diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp index d5d688e705..ca5ba69e8e 100644 --- a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp @@ -577,6 +577,20 @@ TEST_F(CachedSetTest, rendersWithOffsetFramebufferContent) { cachedSet.append(CachedSet(layer3)); } +TEST_F(CachedSetTest, cachingHintIncludesLayersByDefault) { + CachedSet cachedSet(*mTestLayers[0]->cachedSetLayer.get()); + EXPECT_FALSE(cachedSet.cachingHintExcludesLayers()); +} + +TEST_F(CachedSetTest, cachingHintExcludesLayersWhenDisabled) { + CachedSet::Layer& layer1 = *mTestLayers[0]->cachedSetLayer.get(); + mTestLayers[0]->layerFECompositionState.cachingHint = gui::CachingHint::Disabled; + mTestLayers[0]->layerState->update(&mTestLayers[0]->outputLayer); + + CachedSet cachedSet(layer1); + EXPECT_TRUE(cachedSet.cachingHintExcludesLayers()); +} + TEST_F(CachedSetTest, holePunch_requiresBuffer) { CachedSet::Layer& layer1 = *mTestLayers[0]->cachedSetLayer.get(); auto& layerFECompositionState = mTestLayers[0]->layerFECompositionState; diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp index 86cfee6f0a..778a0a8c93 100644 --- a/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp @@ -1112,6 +1112,55 @@ TEST_F(FlattenerRenderSchedulingTest, flattenLayers_renderCachedSets_defersUpToM true); } +TEST_F(FlattenerTest, flattenLayers_skipsLayersDisabledFromCaching) { + auto& layerState1 = mTestLayers[0]->layerState; + const auto& overrideBuffer1 = layerState1->getOutputLayer()->getState().overrideInfo.buffer; + + auto& layerState2 = mTestLayers[1]->layerState; + const auto& overrideBuffer2 = layerState2->getOutputLayer()->getState().overrideInfo.buffer; + + // The third layer has a CachingHint that prevents caching from running + auto& layerState3 = mTestLayers[2]->layerState; + const auto& overrideBuffer3 = layerState3->getOutputLayer()->getState().overrideInfo.buffer; + mTestLayers[2]->layerFECompositionState.cachingHint = gui::CachingHint::Disabled; + mTestLayers[2]->layerState->update(&mTestLayers[2]->outputLayer); + + const std::vector layers = { + layerState1.get(), + layerState2.get(), + layerState3.get(), + }; + + initializeFlattener(layers); + + mTime += 200ms; + initializeOverrideBuffer(layers); + EXPECT_EQ(getNonBufferHash(layers), + mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime)); + + // This will render a CachedSet. + EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)) + .WillOnce(Return(ByMove(ftl::yield(Fence::NO_FENCE)))); + mFlattener->renderCachedSets(mOutputState, std::nullopt, true); + + // We've rendered a CachedSet, but we haven't merged it in. + EXPECT_EQ(nullptr, overrideBuffer1); + EXPECT_EQ(nullptr, overrideBuffer2); + EXPECT_EQ(nullptr, overrideBuffer3); + + // This time we merge the CachedSet in, so we have a new hash, and we should + // only have two sets. + EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _, _)).Times(0); + initializeOverrideBuffer(layers); + EXPECT_NE(getNonBufferHash(layers), + mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime)); + mFlattener->renderCachedSets(mOutputState, std::nullopt, true); + + EXPECT_NE(nullptr, overrideBuffer1); + EXPECT_EQ(overrideBuffer1, overrideBuffer2); + EXPECT_EQ(nullptr, overrideBuffer3); +} + TEST_F(FlattenerTest, flattenLayers_skipsBT601_625) { auto& layerState1 = mTestLayers[0]->layerState; const auto& overrideBuffer1 = layerState1->getOutputLayer()->getState().overrideInfo.buffer; diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp index 47b682059f..044917ead9 100644 --- a/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp @@ -994,6 +994,45 @@ TEST_F(LayerStateTest, hasBlurBehind_withBlurRegion_returnsTrue) { EXPECT_TRUE(mLayerState->hasBlurBehind()); } +TEST_F(LayerStateTest, updateCachingHint) { + OutputLayerCompositionState outputLayerCompositionState; + LayerFECompositionState layerFECompositionState; + layerFECompositionState.cachingHint = gui::CachingHint::Enabled; + setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState, + layerFECompositionState); + mLayerState = std::make_unique(&mOutputLayer); + + mock::OutputLayer newOutputLayer; + sp newLayerFE = sp::make(); + LayerFECompositionState layerFECompositionStateTwo; + layerFECompositionStateTwo.cachingHint = gui::CachingHint::Disabled; + setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState, + layerFECompositionStateTwo); + ftl::Flags updates = mLayerState->update(&newOutputLayer); + EXPECT_EQ(ftl::Flags(LayerStateField::CachingHint), updates); +} + +TEST_F(LayerStateTest, compareCachingHint) { + OutputLayerCompositionState outputLayerCompositionState; + LayerFECompositionState layerFECompositionState; + layerFECompositionState.cachingHint = gui::CachingHint::Enabled; + setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState, + layerFECompositionState); + mLayerState = std::make_unique(&mOutputLayer); + mock::OutputLayer newOutputLayer; + sp newLayerFE = sp::make(); + LayerFECompositionState layerFECompositionStateTwo; + layerFECompositionStateTwo.cachingHint = gui::CachingHint::Disabled; + setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState, + layerFECompositionStateTwo); + auto otherLayerState = std::make_unique(&newOutputLayer); + + verifyNonUniqueDifferingFields(*mLayerState, *otherLayerState, LayerStateField::CachingHint); + + EXPECT_TRUE(mLayerState->compare(*otherLayerState)); + EXPECT_TRUE(otherLayerState->compare(*mLayerState)); +} + TEST_F(LayerStateTest, dumpDoesNotCrash) { OutputLayerCompositionState outputLayerCompositionState; LayerFECompositionState layerFECompositionState; diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp index c9aeb24cf5..d740350cc5 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp +++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp @@ -727,6 +727,7 @@ void LayerSnapshotBuilder::updateSnapshot(LayerSnapshot& snapshot, const Args& a snapshot.dimmingEnabled = requested.dimmingEnabled; snapshot.layerOpaqueFlagSet = (requested.flags & layer_state_t::eLayerOpaque) == layer_state_t::eLayerOpaque; + snapshot.cachingHint = requested.cachingHint; } if (forceUpdate || snapshot.changes.any(RequestedLayerState::Changes::Content)) { diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp index 28340844a3..09523d3ea3 100644 --- a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp +++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp @@ -137,6 +137,7 @@ RequestedLayerState::RequestedLayerState(const LayerCreationArgs& args) dataspace = ui::Dataspace::V0_SRGB; gameMode = gui::GameMode::Unsupported; requestedFrameRate = {}; + cachingHint = gui::CachingHint::Enabled; } void RequestedLayerState::merge(const ResolvedComposerState& resolvedComposerState) { diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 084d9b93db..dac09169c8 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -566,6 +566,7 @@ void Layer::prepareBasicGeometryCompositionState() { : Hwc2::IComposerClient::BlendMode::COVERAGE; } + // Please keep in sync with LayerSnapshotBuilder auto* snapshot = editLayerSnapshot(); snapshot->outputFilter = getOutputFilter(); snapshot->isVisible = isVisible(); @@ -592,6 +593,7 @@ void Layer::prepareGeometryCompositionState() { const auto& drawingState{getDrawingState()}; auto* snapshot = editLayerSnapshot(); + // Please keep in sync with LayerSnapshotBuilder snapshot->geomBufferSize = getBufferSize(drawingState); snapshot->geomContentCrop = getBufferCrop(); snapshot->geomCrop = getCrop(drawingState); @@ -624,6 +626,7 @@ void Layer::prepareGeometryCompositionState() { void Layer::preparePerFrameCompositionState() { const auto& drawingState{getDrawingState()}; + // Please keep in sync with LayerSnapshotBuilder auto* snapshot = editLayerSnapshot(); snapshot->forceClientComposition = false; @@ -637,6 +640,7 @@ void Layer::preparePerFrameCompositionState() { snapshot->dimmingEnabled = isDimmingEnabled(); snapshot->currentSdrHdrRatio = getCurrentSdrHdrRatio(); snapshot->desiredSdrHdrRatio = getDesiredSdrHdrRatio(); + snapshot->cachingHint = getCachingHint(); const bool usesRoundedCorners = hasRoundedCorners(); @@ -666,8 +670,9 @@ void Layer::preparePerFrameCompositionState() { } void Layer::preparePerFrameBufferCompositionState() { - // Sideband layers + // Please keep in sync with LayerSnapshotBuilder auto* snapshot = editLayerSnapshot(); + // Sideband layers if (snapshot->sidebandStream.get() && !snapshot->sidebandStreamHasFrame) { snapshot->compositionType = aidl::android::hardware::graphics::composer3::Composition::SIDEBAND; @@ -690,6 +695,7 @@ void Layer::preparePerFrameBufferCompositionState() { } void Layer::preparePerFrameEffectsCompositionState() { + // Please keep in sync with LayerSnapshotBuilder auto* snapshot = editLayerSnapshot(); snapshot->color = getColor(); snapshot->compositionType = @@ -698,6 +704,7 @@ void Layer::preparePerFrameEffectsCompositionState() { void Layer::prepareCursorCompositionState() { const State& drawingState{getDrawingState()}; + // Please keep in sync with LayerSnapshotBuilder auto* snapshot = editLayerSnapshot(); // Apply the layer's transform, followed by the display's global transform @@ -3091,6 +3098,14 @@ bool Layer::setExtendedRangeBrightness(float currentBufferRatio, float desiredRa return true; } +bool Layer::setCachingHint(gui::CachingHint cachingHint) { + if (mDrawingState.cachingHint == cachingHint) return false; + mDrawingState.cachingHint = cachingHint; + mDrawingState.modified = true; + setTransactionFlags(eTransactionNeeded); + return true; +} + bool Layer::setHdrMetadata(const HdrMetadata& hdrMetadata) { if (mDrawingState.hdrMetadata == hdrMetadata) return false; mDrawingState.hdrMetadata = hdrMetadata; diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 2955dafa0f..7d40774f83 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -227,6 +227,7 @@ public: bool dimmingEnabled = true; float currentSdrHdrRatio = 1.f; float desiredSdrHdrRatio = 1.f; + gui::CachingHint cachingHint = gui::CachingHint::Enabled; }; explicit Layer(const LayerCreationArgs& args); @@ -296,6 +297,7 @@ public: virtual bool isDimmingEnabled() const { return getDrawingState().dimmingEnabled; } float getDesiredSdrHdrRatio() const { return getDrawingState().desiredSdrHdrRatio; } float getCurrentSdrHdrRatio() const { return getDrawingState().currentSdrHdrRatio; } + gui::CachingHint getCachingHint() const { return getDrawingState().cachingHint; } bool setTransform(uint32_t /*transform*/); bool setTransformToDisplayInverse(bool /*transformToDisplayInverse*/); @@ -305,6 +307,7 @@ public: std::optional /* dequeueTime */, const FrameTimelineInfo& /*info*/); bool setDataspace(ui::Dataspace /*dataspace*/); bool setExtendedRangeBrightness(float currentBufferRatio, float desiredRatio); + bool setCachingHint(gui::CachingHint cachingHint); bool setHdrMetadata(const HdrMetadata& /*hdrMetadata*/); bool setSurfaceDamageRegion(const Region& /*surfaceDamage*/); bool setApi(int32_t /*api*/); diff --git a/services/surfaceflinger/LayerFE.h b/services/surfaceflinger/LayerFE.h index 01da0199a2..c23bd31d1a 100644 --- a/services/surfaceflinger/LayerFE.h +++ b/services/surfaceflinger/LayerFE.h @@ -16,6 +16,7 @@ #pragma once +#include #include #include "FrontEnd/LayerSnapshot.h" #include "compositionengine/LayerFE.h" diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 5f95859fd3..5c8579cb4d 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -4783,6 +4783,11 @@ uint32_t SurfaceFlinger::setClientStateLocked(const FrameTimelineInfo& frameTime flags |= eTraversalNeeded; } } + if (what & layer_state_t::eCachingHintChanged) { + if (layer->setCachingHint(s.cachingHint)) { + flags |= eTraversalNeeded; + } + } if (what & layer_state_t::eHdrMetadataChanged) { if (layer->setHdrMetadata(s.hdrMetadata)) flags |= eTraversalNeeded; } -- cgit v1.2.3-59-g8ed1b From d47bceea5a8da823b38eb5ca71bb8206b95c1958 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Fri, 24 Feb 2023 18:08:51 +0000 Subject: SF: Frontend fixes for issues surfaced by SurfaceFlinger_test - separate color and bgcolor in layer state so we don't set a color on a layer without a buffer - avoid using legacy layer state when latching a buffer - fix callback issue where invisible or offscreen layers were not invoking the callbacks - pass in layer snapshot for trusted presentation state - fix a screenshot issue where the root layer was skipped - pass in framerate changes to layer history Test: presubmit Test: atest SurfaceFlinger_test with new fe Bug: 238781169 Change-Id: Id9ff8a036dc283e21a05985c1c01ebd070b1df24 --- libs/gui/LayerState.cpp | 21 ++- libs/gui/SurfaceComposerClient.cpp | 4 +- libs/gui/include/gui/LayerState.h | 13 +- .../compositionengine/LayerFECompositionState.h | 2 - .../CompositionEngine/src/Output.cpp | 4 +- .../surfaceflinger/FrontEnd/LayerCreationArgs.cpp | 15 ++- .../surfaceflinger/FrontEnd/LayerCreationArgs.h | 6 +- services/surfaceflinger/FrontEnd/LayerHierarchy.h | 6 + .../FrontEnd/LayerLifecycleManager.cpp | 28 ++-- services/surfaceflinger/FrontEnd/LayerSnapshot.cpp | 3 +- .../FrontEnd/LayerSnapshotBuilder.cpp | 79 ++++++++---- .../surfaceflinger/FrontEnd/LayerSnapshotBuilder.h | 7 +- .../FrontEnd/RequestedLayerState.cpp | 31 ++++- .../surfaceflinger/FrontEnd/RequestedLayerState.h | 7 + services/surfaceflinger/Layer.cpp | 30 ++++- services/surfaceflinger/Layer.h | 7 +- services/surfaceflinger/SurfaceFlinger.cpp | 143 ++++++++++++++------- services/surfaceflinger/SurfaceFlinger.h | 1 + .../Tracing/TransactionProtoParser.cpp | 16 +-- .../tests/LayerRenderTypeTransaction_test.cpp | 1 + services/surfaceflinger/tests/MirrorLayer_test.cpp | 16 ++- .../tests/unittests/LayerHierarchyTest.cpp | 7 +- .../tests/unittests/LayerHierarchyTest.h | 2 +- .../tests/unittests/LayerLifecycleManagerTest.cpp | 23 ++-- 24 files changed, 324 insertions(+), 148 deletions(-) (limited to 'libs/gui/LayerState.cpp') diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index f6bba16899..b391337d1d 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -74,7 +74,7 @@ layer_state_t::layer_state_t() surfaceDamageRegion(), api(-1), colorTransform(mat4()), - bgColorAlpha(0), + bgColor(0), bgColorDataspace(ui::Dataspace::UNKNOWN), colorSpaceAgnostic(false), shadowRadius(0.0f), @@ -140,7 +140,10 @@ status_t layer_state_t::write(Parcel& output) const SAFE_PARCEL(output.writeFloat, cornerRadius); SAFE_PARCEL(output.writeUint32, backgroundBlurRadius); SAFE_PARCEL(output.writeParcelable, metadata); - SAFE_PARCEL(output.writeFloat, bgColorAlpha); + SAFE_PARCEL(output.writeFloat, bgColor.r); + SAFE_PARCEL(output.writeFloat, bgColor.g); + SAFE_PARCEL(output.writeFloat, bgColor.b); + SAFE_PARCEL(output.writeFloat, bgColor.a); SAFE_PARCEL(output.writeUint32, static_cast(bgColorDataspace)); SAFE_PARCEL(output.writeBool, colorSpaceAgnostic); SAFE_PARCEL(output.writeVectorSize, listeners); @@ -259,7 +262,14 @@ status_t layer_state_t::read(const Parcel& input) SAFE_PARCEL(input.readUint32, &backgroundBlurRadius); SAFE_PARCEL(input.readParcelable, &metadata); - SAFE_PARCEL(input.readFloat, &bgColorAlpha); + SAFE_PARCEL(input.readFloat, &tmpFloat); + bgColor.r = tmpFloat; + SAFE_PARCEL(input.readFloat, &tmpFloat); + bgColor.g = tmpFloat; + SAFE_PARCEL(input.readFloat, &tmpFloat); + bgColor.b = tmpFloat; + SAFE_PARCEL(input.readFloat, &tmpFloat); + bgColor.a = tmpFloat; SAFE_PARCEL(input.readUint32, &tmpUint32); bgColorDataspace = static_cast(tmpUint32); SAFE_PARCEL(input.readBool, &colorSpaceAgnostic); @@ -618,8 +628,7 @@ void layer_state_t::merge(const layer_state_t& other) { } if (other.what & eBackgroundColorChanged) { what |= eBackgroundColorChanged; - color.rgb = other.color.rgb; - bgColorAlpha = other.bgColorAlpha; + bgColor = other.bgColor; bgColorDataspace = other.bgColorDataspace; } if (other.what & eMetadataChanged) { @@ -752,7 +761,7 @@ uint64_t layer_state_t::diff(const layer_state_t& other) const { CHECK_DIFF(diff, eColorTransformChanged, other, colorTransform); if (other.what & eHasListenerCallbacksChanged) diff |= eHasListenerCallbacksChanged; if (other.what & eInputInfoChanged) diff |= eInputInfoChanged; - CHECK_DIFF3(diff, eBackgroundColorChanged, other, color.rgb, bgColorAlpha, bgColorDataspace); + CHECK_DIFF2(diff, eBackgroundColorChanged, other, bgColor, bgColorDataspace); if (other.what & eMetadataChanged) diff |= eMetadataChanged; CHECK_DIFF(diff, eShadowRadiusChanged, other, shadowRadius); CHECK_DIFF3(diff, eRenderBorderChanged, other, borderEnabled, borderWidth, borderColor); diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 001d475823..0f138ca157 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1560,8 +1560,8 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBackg } s->what |= layer_state_t::eBackgroundColorChanged; - s->color.rgb = color; - s->bgColorAlpha = alpha; + s->bgColor.rgb = color; + s->bgColor.a = alpha; s->bgColorDataspace = dataspace; registerSurfaceControlForCallback(sc); diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index da144bd191..29fb989743 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -226,9 +226,9 @@ struct layer_state_t { bool hasBufferChanges() const; // Layer hierarchy updates. - static constexpr uint64_t HIERARCHY_CHANGES = layer_state_t::eBackgroundColorChanged | - layer_state_t::eLayerChanged | layer_state_t::eRelativeLayerChanged | - layer_state_t::eReparent; + static constexpr uint64_t HIERARCHY_CHANGES = layer_state_t::eLayerChanged | + layer_state_t::eRelativeLayerChanged | layer_state_t::eReparent | + layer_state_t::eLayerStackChanged; // Geometry updates. static constexpr uint64_t GEOMETRY_CHANGES = layer_state_t::eBufferCropChanged | @@ -264,9 +264,8 @@ struct layer_state_t { static constexpr uint64_t AFFECTS_CHILDREN = layer_state_t::GEOMETRY_CHANGES | layer_state_t::HIERARCHY_CHANGES | layer_state_t::eAlphaChanged | layer_state_t::eColorTransformChanged | layer_state_t::eCornerRadiusChanged | - layer_state_t::eFlagsChanged | layer_state_t::eLayerStackChanged | - layer_state_t::eTrustedOverlayChanged | layer_state_t::eFrameRateChanged | - layer_state_t::eFixedTransformHintChanged; + layer_state_t::eFlagsChanged | layer_state_t::eTrustedOverlayChanged | + layer_state_t::eFrameRateChanged | layer_state_t::eFixedTransformHintChanged; // Changes affecting data sent to input. static constexpr uint64_t INPUT_CHANGES = layer_state_t::GEOMETRY_CHANGES | @@ -333,7 +332,7 @@ struct layer_state_t { // The following refer to the alpha, and dataspace, respectively of // the background color layer - float bgColorAlpha; + half4 bgColor; ui::Dataspace bgColorDataspace; // A color space agnostic layer means the color of this layer can be diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h index 0b4d20c660..eae5871477 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h @@ -213,9 +213,7 @@ struct LayerFECompositionState { float currentSdrHdrRatio = 1.f; float desiredSdrHdrRatio = 1.f; - bool isInternalDisplayOverlay = false; gui::CachingHint cachingHint = gui::CachingHint::Enabled; - virtual ~LayerFECompositionState(); // Debugging diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index 7d9431605d..175dd1d825 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -538,8 +538,8 @@ void Output::ensureOutputLayerIfVisible(sp& layerFE, return; } - bool computeAboveCoveredExcludingOverlays = - coverage.aboveCoveredLayersExcludingOverlays && !layerFEState->isInternalDisplayOverlay; + bool computeAboveCoveredExcludingOverlays = coverage.aboveCoveredLayersExcludingOverlays && + !layerFEState->outputFilter.toInternalDisplay; /* * opaqueRegion: area of a surface that is fully opaque. diff --git a/services/surfaceflinger/FrontEnd/LayerCreationArgs.cpp b/services/surfaceflinger/FrontEnd/LayerCreationArgs.cpp index 6d492c0f4a..66598251cb 100644 --- a/services/surfaceflinger/FrontEnd/LayerCreationArgs.cpp +++ b/services/surfaceflinger/FrontEnd/LayerCreationArgs.cpp @@ -24,9 +24,13 @@ namespace android::surfaceflinger { std::atomic LayerCreationArgs::sSequence{1}; +uint32_t LayerCreationArgs::getInternalLayerId(uint32_t id) { + return id | INTERNAL_LAYER_PREFIX; +} + LayerCreationArgs::LayerCreationArgs(SurfaceFlinger* flinger, sp client, std::string name, uint32_t flags, gui::LayerMetadata metadataArg, - std::optional id) + std::optional id, bool internalLayer) : flinger(flinger), client(std::move(client)), name(std::move(name)), @@ -46,10 +50,15 @@ LayerCreationArgs::LayerCreationArgs(SurfaceFlinger* flinger, sp client, if (id) { sequence = *id; - sSequence = *id + 1; + if (internalLayer) { + sequence = getInternalLayerId(*id); + } else { + sSequence = *id + 1; + } } else { sequence = sSequence++; - if (sequence == UNASSIGNED_LAYER_ID) { + if (sequence >= INTERNAL_LAYER_PREFIX) { + sSequence = 1; ALOGW("Layer sequence id rolled over."); sequence = sSequence++; } diff --git a/services/surfaceflinger/FrontEnd/LayerCreationArgs.h b/services/surfaceflinger/FrontEnd/LayerCreationArgs.h index 9d2aaab23d..2cd6b55bc4 100644 --- a/services/surfaceflinger/FrontEnd/LayerCreationArgs.h +++ b/services/surfaceflinger/FrontEnd/LayerCreationArgs.h @@ -25,6 +25,7 @@ #include constexpr uint32_t UNASSIGNED_LAYER_ID = std::numeric_limits::max(); +constexpr uint32_t INTERNAL_LAYER_PREFIX = 1u << 31; namespace android { class SurfaceFlinger; @@ -35,10 +36,11 @@ namespace android::surfaceflinger { struct LayerCreationArgs { static std::atomic sSequence; + static uint32_t getInternalLayerId(uint32_t id); LayerCreationArgs(android::SurfaceFlinger*, sp, std::string name, - uint32_t flags, gui::LayerMetadata, - std::optional id = std::nullopt); + uint32_t flags, gui::LayerMetadata, std::optional id = std::nullopt, + bool internalLayer = false); LayerCreationArgs(const LayerCreationArgs&); android::SurfaceFlinger* flinger; diff --git a/services/surfaceflinger/FrontEnd/LayerHierarchy.h b/services/surfaceflinger/FrontEnd/LayerHierarchy.h index 2ab897b35d..0f700a9423 100644 --- a/services/surfaceflinger/FrontEnd/LayerHierarchy.h +++ b/services/surfaceflinger/FrontEnd/LayerHierarchy.h @@ -128,12 +128,18 @@ public: // Traverse the hierarchy and visit all child variants. void traverse(const Visitor& visitor) const { TraversalPath root = TraversalPath::ROOT; + if (mLayer) { + root.id = mLayer->id; + } traverse(visitor, root); } // Traverse the hierarchy in z-order, skipping children that have relative parents. void traverseInZOrder(const Visitor& visitor) const { TraversalPath root = TraversalPath::ROOT; + if (mLayer) { + root.id = mLayer->id; + } traverseInZOrder(visitor, root); } diff --git a/services/surfaceflinger/FrontEnd/LayerLifecycleManager.cpp b/services/surfaceflinger/FrontEnd/LayerLifecycleManager.cpp index 66197be44a..79ffcbf65d 100644 --- a/services/surfaceflinger/FrontEnd/LayerLifecycleManager.cpp +++ b/services/surfaceflinger/FrontEnd/LayerLifecycleManager.cpp @@ -192,35 +192,38 @@ void LayerLifecycleManager::applyTransactions(const std::vectormerge(resolvedComposerState); if (layer->what & layer_state_t::eBackgroundColorChanged) { - if (layer->bgColorLayerId == UNASSIGNED_LAYER_ID && layer->bgColorAlpha != 0) { + if (layer->bgColorLayerId == UNASSIGNED_LAYER_ID && layer->bgColor.a != 0) { LayerCreationArgs backgroundLayerArgs{nullptr, nullptr, layer->name + "BackgroundColorLayer", ISurfaceComposerClient::eFXSurfaceEffect, - {}}; + {}, + layer->id, + /*internalLayer=*/true}; std::vector> newLayers; newLayers.emplace_back( std::make_unique(backgroundLayerArgs)); RequestedLayerState* backgroundLayer = newLayers.back().get(); + backgroundLayer->bgColorLayer = true; backgroundLayer->handleAlive = false; backgroundLayer->parentId = layer->id; backgroundLayer->z = std::numeric_limits::min(); - backgroundLayer->color.rgb = layer->color.rgb; - backgroundLayer->color.a = layer->bgColorAlpha; + backgroundLayer->color = layer->bgColor; backgroundLayer->dataspace = layer->bgColorDataspace; - layer->bgColorLayerId = backgroundLayer->id; addLayers({std::move(newLayers)}); - } else if (layer->bgColorLayerId != UNASSIGNED_LAYER_ID && - layer->bgColorAlpha == 0) { + } else if (layer->bgColorLayerId != UNASSIGNED_LAYER_ID && layer->bgColor.a == 0) { RequestedLayerState* bgColorLayer = getLayerFromId(layer->bgColorLayerId); - bgColorLayer->parentId = UNASSIGNED_LAYER_ID; - onHandlesDestroyed({layer->bgColorLayerId}); + layer->bgColorLayerId = UNASSIGNED_LAYER_ID; + bgColorLayer->parentId = unlinkLayer(bgColorLayer->parentId, bgColorLayer->id); + onHandlesDestroyed({bgColorLayer->id}); } else if (layer->bgColorLayerId != UNASSIGNED_LAYER_ID) { RequestedLayerState* bgColorLayer = getLayerFromId(layer->bgColorLayerId); - bgColorLayer->color.rgb = layer->color.rgb; - bgColorLayer->color.a = layer->bgColorAlpha; + bgColorLayer->color = layer->bgColor; bgColorLayer->dataspace = layer->bgColorDataspace; + bgColorLayer->what |= layer_state_t::eColorChanged | + layer_state_t::eDataspaceChanged | layer_state_t::eAlphaChanged; + bgColorLayer->changes |= RequestedLayerState::Changes::Content; mGlobalChanges |= RequestedLayerState::Changes::Content; } } @@ -256,8 +259,7 @@ void LayerLifecycleManager::commitChanges() { listener->onLayerAdded(*layer); } } - layer->what = 0; - layer->changes.clear(); + layer->clearChanges(); } for (auto& destroyedLayer : mDestroyedLayers) { diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp index dbb7fbf462..f8661758c1 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp +++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp @@ -139,7 +139,8 @@ std::string LayerSnapshot::getIsVisibleReason() const { // visible std::stringstream reason; if (sidebandStream != nullptr) reason << " sidebandStream"; - if (externalTexture != nullptr) reason << " buffer"; + if (externalTexture != nullptr) + reason << " buffer:" << externalTexture->getId() << " frame:" << frameNumber; if (fillsColor() || color.a > 0.0f) reason << " color{" << color << "}"; if (drawShadows()) reason << " shadowSettings.length=" << shadowSettings.length; if (backgroundBlurRadius > 0) reason << " backgroundBlurRadius=" << backgroundBlurRadius; diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp index d740350cc5..c7f9aa7b42 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp +++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp @@ -337,12 +337,12 @@ LayerSnapshot LayerSnapshotBuilder::getRootSnapshot() { LayerSnapshotBuilder::LayerSnapshotBuilder() : mRootSnapshot(getRootSnapshot()) {} LayerSnapshotBuilder::LayerSnapshotBuilder(Args args) : LayerSnapshotBuilder() { - args.forceUpdate = true; + args.forceUpdate = ForceUpdateFlags::ALL; updateSnapshots(args); } bool LayerSnapshotBuilder::tryFastUpdate(const Args& args) { - if (args.forceUpdate || args.displayChanges) { + if (args.forceUpdate != ForceUpdateFlags::NONE || args.displayChanges) { // force update requested, or we have display changes, so skip the fast path return false; } @@ -393,19 +393,31 @@ void LayerSnapshotBuilder::updateSnapshots(const Args& args) { ATRACE_NAME("UpdateSnapshots"); if (args.parentCrop) { mRootSnapshot.geomLayerBounds = *args.parentCrop; - } else if (args.forceUpdate || args.displayChanges) { + } else if (args.forceUpdate == ForceUpdateFlags::ALL || args.displayChanges) { mRootSnapshot.geomLayerBounds = getMaxDisplayBounds(args.displays); } if (args.displayChanges) { mRootSnapshot.changes = RequestedLayerState::Changes::AffectsChildren | RequestedLayerState::Changes::Geometry; } + if (args.forceUpdate == ForceUpdateFlags::HIERARCHY) { + mRootSnapshot.changes |= + RequestedLayerState::Changes::Hierarchy | RequestedLayerState::Changes::Visibility; + } LayerHierarchy::TraversalPath root = LayerHierarchy::TraversalPath::ROOT; - for (auto& [childHierarchy, variant] : args.root.mChildren) { - LayerHierarchy::ScopedAddToTraversalPath addChildToPath(root, - childHierarchy->getLayer()->id, - variant); - updateSnapshotsInHierarchy(args, *childHierarchy, root, mRootSnapshot); + if (args.root.getLayer()) { + // The hierarchy can have a root layer when used for screenshots otherwise, it will have + // multiple children. + LayerHierarchy::ScopedAddToTraversalPath addChildToPath(root, args.root.getLayer()->id, + LayerHierarchy::Variant::Attached); + updateSnapshotsInHierarchy(args, args.root, root, mRootSnapshot); + } else { + for (auto& [childHierarchy, variant] : args.root.mChildren) { + LayerHierarchy::ScopedAddToTraversalPath addChildToPath(root, + childHierarchy->getLayer()->id, + variant); + updateSnapshotsInHierarchy(args, *childHierarchy, root, mRootSnapshot); + } } sortSnapshotsByZ(args); @@ -451,6 +463,7 @@ const LayerSnapshot& LayerSnapshotBuilder::updateSnapshotsInHierarchy( if (newSnapshot) { snapshot = createSnapshot(traversalPath, *layer); } + scheduler::LayerInfo::FrameRate oldFrameRate = snapshot->frameRate; if (traversalPath.isRelative()) { bool parentIsRelative = traversalPath.variant == LayerHierarchy::Variant::Relative; updateRelativeState(*snapshot, parentSnapshot, parentIsRelative, args); @@ -469,6 +482,10 @@ const LayerSnapshot& LayerSnapshotBuilder::updateSnapshotsInHierarchy( updateSnapshotsInHierarchy(args, *childHierarchy, traversalPath, *snapshot); updateChildState(*snapshot, childSnapshot, args); } + + if (oldFrameRate == snapshot->frameRate) { + snapshot->changes.clear(RequestedLayerState::Changes::FrameRate); + } return *snapshot; } @@ -495,7 +512,7 @@ LayerSnapshot* LayerSnapshotBuilder::createSnapshot(const LayerHierarchy::Traver } void LayerSnapshotBuilder::sortSnapshotsByZ(const Args& args) { - if (!mResortSnapshots && !args.forceUpdate && + if (!mResortSnapshots && args.forceUpdate == ForceUpdateFlags::NONE && !args.layerLifecycleManager.getGlobalChanges().any( RequestedLayerState::Changes::Hierarchy | RequestedLayerState::Changes::Visibility)) { @@ -569,7 +586,8 @@ void LayerSnapshotBuilder::updateChildState(LayerSnapshot& snapshot, if (snapshot.childState.hasValidFrameRate) { return; } - if (args.forceUpdate || childSnapshot.changes.test(RequestedLayerState::Changes::FrameRate)) { + if (args.forceUpdate == ForceUpdateFlags::ALL || + childSnapshot.changes.test(RequestedLayerState::Changes::FrameRate)) { // We return whether this layer ot its children has a vote. We ignore ExactOrMultiple votes // for the same reason we are allowing touch boost for those layers. See // RefreshRateSelector::rankFrameRates for details. @@ -618,21 +636,20 @@ void LayerSnapshotBuilder::updateSnapshot(LayerSnapshot& snapshot, const Args& a ftl::Flags parentChanges = parentSnapshot.changes & (RequestedLayerState::Changes::Hierarchy | RequestedLayerState::Changes::Geometry | RequestedLayerState::Changes::Visibility | RequestedLayerState::Changes::Metadata | - RequestedLayerState::Changes::AffectsChildren); + RequestedLayerState::Changes::AffectsChildren | + RequestedLayerState::Changes::FrameRate); snapshot.changes = parentChanges | requested.changes; snapshot.isHiddenByPolicyFromParent = parentSnapshot.isHiddenByPolicyFromParent || parentSnapshot.invalidTransform || requested.isHiddenByPolicy() || (args.excludeLayerIds.find(path.id) != args.excludeLayerIds.end()); snapshot.contentDirty = requested.what & layer_state_t::CONTENT_DIRTY; // TODO(b/238781169) scope down the changes to only buffer updates. - snapshot.hasReadyFrame = - (snapshot.contentDirty || requested.autoRefresh) && (requested.externalTexture); - // TODO(b/238781169) how is this used? ag/15523870 - snapshot.sidebandStreamHasFrame = false; + snapshot.hasReadyFrame = requested.hasReadyFrame(); + snapshot.sidebandStreamHasFrame = requested.hasSidebandStreamFrame(); updateSurfaceDamage(requested, snapshot.hasReadyFrame, args.forceFullDamage, snapshot.surfaceDamage); - const bool forceUpdate = newSnapshot || args.forceUpdate || + const bool forceUpdate = newSnapshot || args.forceUpdate == ForceUpdateFlags::ALL || snapshot.changes.any(RequestedLayerState::Changes::Visibility | RequestedLayerState::Changes::Created); snapshot.outputFilter.layerStack = requested.parentId != UNASSIGNED_LAYER_ID @@ -708,11 +725,6 @@ void LayerSnapshotBuilder::updateSnapshot(LayerSnapshot& snapshot, const Args& a snapshot.gameMode = requested.metadata.has(gui::METADATA_GAME_MODE) ? requested.gameMode : parentSnapshot.gameMode; - snapshot.frameRate = (requested.requestedFrameRate.rate.isValid() || - (requested.requestedFrameRate.type == - scheduler::LayerInfo::FrameRateCompatibility::NoVote)) - ? requested.requestedFrameRate - : parentSnapshot.frameRate; snapshot.fixedTransformHint = requested.fixedTransformHint != ui::Transform::ROT_INVALID ? requested.fixedTransformHint : parentSnapshot.fixedTransformHint; @@ -722,6 +734,16 @@ void LayerSnapshotBuilder::updateSnapshot(LayerSnapshot& snapshot, const Args& a (requested.layerStackToMirror != ui::INVALID_LAYER_STACK); } + if (forceUpdate || + snapshot.changes.any(RequestedLayerState::Changes::FrameRate | + RequestedLayerState::Changes::Hierarchy)) { + snapshot.frameRate = (requested.requestedFrameRate.rate.isValid() || + (requested.requestedFrameRate.type == + scheduler::LayerInfo::FrameRateCompatibility::NoVote)) + ? requested.requestedFrameRate + : parentSnapshot.frameRate; + } + if (forceUpdate || requested.changes.get() != 0) { snapshot.compositionType = requested.getCompositionType(); snapshot.dimmingEnabled = requested.dimmingEnabled; @@ -773,10 +795,11 @@ void LayerSnapshotBuilder::updateSnapshot(LayerSnapshot& snapshot, const Args& a // snapshot.metadata; LLOGV(snapshot.sequence, "%supdated [%d]%s changes parent:%s global:%s local:%s requested:%s %s from parent %s", - args.forceUpdate ? "Force " : "", requested.id, requested.name.c_str(), - parentSnapshot.changes.string().c_str(), snapshot.changes.string().c_str(), - requested.changes.string().c_str(), std::to_string(requested.what).c_str(), - snapshot.getDebugString().c_str(), parentSnapshot.getDebugString().c_str()); + args.forceUpdate == ForceUpdateFlags::ALL ? "Force " : "", requested.id, + requested.name.c_str(), parentSnapshot.changes.string().c_str(), + snapshot.changes.string().c_str(), requested.changes.string().c_str(), + std::to_string(requested.what).c_str(), snapshot.getDebugString().c_str(), + parentSnapshot.getDebugString().c_str()); } void LayerSnapshotBuilder::updateRoundedCorner(LayerSnapshot& snapshot, @@ -912,8 +935,12 @@ void LayerSnapshotBuilder::updateInput(LayerSnapshot& snapshot, } else { snapshot.inputInfo = {}; } - snapshot.inputInfo.displayId = static_cast(snapshot.outputFilter.layerStack.id); + snapshot.inputInfo.name = requested.name; + snapshot.inputInfo.id = static_cast(requested.id); + snapshot.inputInfo.ownerUid = static_cast(requested.ownerUid); + snapshot.inputInfo.ownerPid = requested.ownerPid; + snapshot.inputInfo.displayId = static_cast(snapshot.outputFilter.layerStack.id); if (!needsInputInfo(snapshot, requested)) { return; } diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h index 0902ab8067..d70bdb9920 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h +++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h @@ -35,10 +35,15 @@ namespace android::surfaceflinger::frontend { // snapshots when there are only buffer updates. class LayerSnapshotBuilder { public: + enum class ForceUpdateFlags { + NONE, + ALL, + HIERARCHY, + }; struct Args { LayerHierarchy root; const LayerLifecycleManager& layerLifecycleManager; - bool forceUpdate = false; + ForceUpdateFlags forceUpdate = ForceUpdateFlags::NONE; bool includeMetadata = false; const display::DisplayMap& displays; // Set to true if there were display changes since last update. diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp index 09523d3ea3..e2cbe28893 100644 --- a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp +++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp @@ -165,8 +165,13 @@ void RequestedLayerState::merge(const ResolvedComposerState& resolvedComposerSta if (hadBufferOrSideStream != hasBufferOrSideStream) { changes |= RequestedLayerState::Changes::Geometry | RequestedLayerState::Changes::VisibleRegion | - RequestedLayerState::Changes::Visibility | RequestedLayerState::Changes::Input | - RequestedLayerState::Changes::Buffer; + RequestedLayerState::Changes::Visibility | RequestedLayerState::Changes::Input; + } + if (clientState.what & layer_state_t::eBufferChanged) { + changes |= RequestedLayerState::Changes::Buffer; + } + if (clientState.what & layer_state_t::eSidebandStreamChanged) { + changes |= RequestedLayerState::Changes::SidebandStream; } } if (what & (layer_state_t::eAlphaChanged)) { @@ -197,7 +202,9 @@ void RequestedLayerState::merge(const ResolvedComposerState& resolvedComposerSta static const mat4 identityMatrix = mat4(); hasColorTransform = colorTransform != identityMatrix; } - if (clientState.what & (layer_state_t::eLayerChanged | layer_state_t::eRelativeLayerChanged)) { + if (clientState.what & + (layer_state_t::eLayerChanged | layer_state_t::eRelativeLayerChanged | + layer_state_t::eLayerStackChanged)) { changes |= RequestedLayerState::Changes::Z; } if (clientState.what & layer_state_t::eReparent) { @@ -453,4 +460,22 @@ bool RequestedLayerState::hasBlur() const { return backgroundBlurRadius > 0 || blurRegions.size() > 0; } +bool RequestedLayerState::hasFrameUpdate() const { + return what & layer_state_t::CONTENT_DIRTY && + (externalTexture || bgColorLayerId != UNASSIGNED_LAYER_ID); +} + +bool RequestedLayerState::hasReadyFrame() const { + return hasFrameUpdate() || changes.test(Changes::SidebandStream) || autoRefresh; +} + +bool RequestedLayerState::hasSidebandStreamFrame() const { + return hasFrameUpdate() && sidebandStream.get(); +} + +void RequestedLayerState::clearChanges() { + what = 0; + changes.clear(); +} + } // namespace android::surfaceflinger::frontend diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.h b/services/surfaceflinger/FrontEnd/RequestedLayerState.h index 6840b25a5b..8b475a3e45 100644 --- a/services/surfaceflinger/FrontEnd/RequestedLayerState.h +++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.h @@ -52,10 +52,13 @@ struct RequestedLayerState : layer_state_t { FrameRate = 1u << 13, VisibleRegion = 1u << 14, Buffer = 1u << 15, + SidebandStream = 1u << 16, }; static Rect reduce(const Rect& win, const Region& exclude); RequestedLayerState(const LayerCreationArgs&); void merge(const ResolvedComposerState&); + void clearChanges(); + // Currently we only care about the primary display ui::Transform getTransform(uint32_t displayRotationFlags) const; ui::Size getUnrotatedBufferSize(uint32_t displayRotationFlags) const; @@ -72,6 +75,9 @@ struct RequestedLayerState : layer_state_t { bool hasValidRelativeParent() const; bool hasInputInfo() const; bool hasBlur() const; + bool hasFrameUpdate() const; + bool hasReadyFrame() const; + bool hasSidebandStreamFrame() const; // Layer serial number. This gives layers an explicit ordering, so we // have a stable sort order when their layer stack and Z-order are @@ -110,6 +116,7 @@ struct RequestedLayerState : layer_state_t { uint32_t touchCropId = UNASSIGNED_LAYER_ID; uint32_t bgColorLayerId = UNASSIGNED_LAYER_ID; ftl::Flags changes; + bool bgColorLayer = false; }; } // namespace android::surfaceflinger::frontend diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index dac09169c8..5ee701d617 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -2512,7 +2512,20 @@ bool Layer::hasInputInfo() const { compositionengine::OutputLayer* Layer::findOutputLayerForDisplay( const DisplayDevice* display) const { if (!display) return nullptr; - return display->getCompositionDisplay()->getOutputLayerForLayer(getCompositionEngineLayerFE()); + if (!mFlinger->mLayerLifecycleManagerEnabled) { + return display->getCompositionDisplay()->getOutputLayerForLayer( + getCompositionEngineLayerFE()); + } + sp layerFE; + frontend::LayerHierarchy::TraversalPath path{.id = static_cast(sequence)}; + for (auto& [p, layer] : mLayerFEs) { + if (p == path) { + layerFE = layer; + } + } + + if (!layerFE) return nullptr; + return display->getCompositionDisplay()->getOutputLayerForLayer(layerFE); } Region Layer::getVisibleRegion(const DisplayDevice* display) const { @@ -3275,11 +3288,11 @@ bool Layer::hasFrameUpdate() const { (c.buffer != nullptr || c.bgColorLayer != nullptr); } -void Layer::updateTexImage(nsecs_t latchTime) { +void Layer::updateTexImage(nsecs_t latchTime, bool bgColorOnly) { const State& s(getDrawingState()); if (!s.buffer) { - if (s.bgColorLayer) { + if (bgColorOnly) { for (auto& handle : mDrawingState.callbackHandles) { handle->latchTime = latchTime; } @@ -3476,7 +3489,7 @@ bool Layer::simpleBufferUpdate(const layer_state_t& s) const { } if (s.what & layer_state_t::eBackgroundColorChanged) { - if (mDrawingState.bgColorLayer || s.bgColorAlpha != 0) { + if (mDrawingState.bgColorLayer || s.bgColor.a != 0) { ALOGV("%s: false [eBackgroundColorChanged changed]", __func__); return false; } @@ -3800,6 +3813,11 @@ void Layer::onPostComposition(const DisplayDevice* display, } bool Layer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime) { + const bool bgColorOnly = mDrawingState.bgColorLayer != nullptr; + return latchBufferImpl(recomputeVisibleRegions, latchTime, bgColorOnly); +} + +bool Layer::latchBufferImpl(bool& recomputeVisibleRegions, nsecs_t latchTime, bool bgColorOnly) { ATRACE_FORMAT_INSTANT("latchBuffer %s - %" PRIu64, getDebugName(), getDrawingState().frameNumber); @@ -3816,8 +3834,7 @@ bool Layer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime) { mFlinger->onLayerUpdate(); return false; } - - updateTexImage(latchTime); + updateTexImage(latchTime, bgColorOnly); if (mDrawingState.buffer == nullptr) { return false; } @@ -4021,7 +4038,6 @@ void Layer::updateSnapshot(bool updateGeometry) { snapshot->bufferSize = getBufferSize(mDrawingState); snapshot->externalTexture = mBufferInfo.mBuffer; snapshot->hasReadyFrame = hasReadyFrame(); - snapshot->isInternalDisplayOverlay = isInternalDisplayOverlay(); preparePerFrameCompositionState(); } diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 7d40774f83..9b7a4059ca 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -427,6 +427,9 @@ public: */ bool latchBuffer(bool& /*recomputeVisibleRegions*/, nsecs_t /*latchTime*/); + bool latchBufferImpl(bool& /*recomputeVisibleRegions*/, nsecs_t /*latchTime*/, + bool bgColorOnly); + /* * Calls latchBuffer if the buffer has a frame queued and then releases the buffer. * This is used if the buffer is just latched and releases to free up the buffer @@ -846,6 +849,7 @@ public: void callReleaseBufferCallback(const sp& listener, const sp& buffer, uint64_t framenumber, const sp& releaseFence); + bool setFrameRateForLayerTree(FrameRate); protected: // For unit tests @@ -1018,7 +1022,6 @@ private: void updateTreeHasFrameRateVote(); bool propagateFrameRateForLayerTree(FrameRate parentFrameRate, bool* transactionNeeded); - bool setFrameRateForLayerTree(FrameRate); void setZOrderRelativeOf(const wp& relativeOf); bool isTrustedOverlay() const; gui::DropInputMode getDropInputMode() const; @@ -1046,7 +1049,7 @@ private: bool hasFrameUpdate() const; - void updateTexImage(nsecs_t latchTime); + void updateTexImage(nsecs_t latchTime, bool bgColorOnly = false); // Crop that applies to the buffer Rect computeBufferCrop(const State& s); diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 5c8579cb4d..29af6d1b7a 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2192,7 +2192,8 @@ bool SurfaceFlinger::updateLayerSnapshots(VsyncId vsyncId, LifecycleUpdate& upda mLayerLifecycleManager.getDestroyedLayers()); } - applyAndCommitDisplayTransactionStates(update.transactions); + bool mustComposite = false; + mustComposite |= applyAndCommitDisplayTransactionStates(update.transactions); { ATRACE_NAME("LayerSnapshotBuilder:update"); @@ -2216,23 +2217,37 @@ bool SurfaceFlinger::updateLayerSnapshots(VsyncId vsyncId, LifecycleUpdate& upda mVisibleRegionsDirty = true; } outTransactionsAreEmpty = mLayerLifecycleManager.getGlobalChanges().get() == 0; - const bool mustComposite = mLayerLifecycleManager.getGlobalChanges().get() != 0; - { - ATRACE_NAME("LLM:commitChanges"); - mLayerLifecycleManager.commitChanges(); - } + mustComposite |= mLayerLifecycleManager.getGlobalChanges().get() != 0; + bool newDataLatched = false; if (!mLegacyFrontEndEnabled) { ATRACE_NAME("DisplayCallbackAndStatsUpdates"); applyTransactions(update.transactions, vsyncId); + const nsecs_t latchTime = systemTime(); + bool unused = false; + + for (auto& layer : mLayerLifecycleManager.getLayers()) { + if (layer->changes.test(frontend::RequestedLayerState::Changes::Created) && + layer->bgColorLayer) { + sp bgColorLayer = getFactory().createEffectLayer( + LayerCreationArgs(this, nullptr, layer->name, + ISurfaceComposerClient::eFXSurfaceEffect, LayerMetadata(), + std::make_optional(layer->parentId), true)); + mLegacyLayers[bgColorLayer->sequence] = bgColorLayer; + } + if (!layer->hasReadyFrame()) continue; - bool newDataLatched = false; - for (auto& snapshot : mLayerSnapshotBuilder.getSnapshots()) { - if (!snapshot->changes.test(Changes::Buffer)) continue; - auto it = mLegacyLayers.find(snapshot->sequence); + auto it = mLegacyLayers.find(layer->id); LOG_ALWAYS_FATAL_IF(it == mLegacyLayers.end(), "Couldnt find layer object for %s", - snapshot->getDebugString().c_str()); + layer->getDebugString().c_str()); + const bool bgColorOnly = + !layer->externalTexture && (layer->bgColorLayerId != UNASSIGNED_LAYER_ID); + it->second->latchBufferImpl(unused, latchTime, bgColorOnly); mLayersWithQueuedFrames.emplace(it->second); + } + + for (auto& snapshot : mLayerSnapshotBuilder.getSnapshots()) { + if (!snapshot->hasReadyFrame) continue; newDataLatched = true; if (!snapshot->isVisible) break; @@ -2245,6 +2260,11 @@ bool SurfaceFlinger::updateLayerSnapshots(VsyncId vsyncId, LifecycleUpdate& upda mLegacyLayers.erase(destroyedLayer->id); } + { + ATRACE_NAME("LLM:commitChanges"); + mLayerLifecycleManager.commitChanges(); + } + // enter boot animation on first buffer latch if (CC_UNLIKELY(mBootStage == BootStage::BOOTLOADER && newDataLatched)) { ALOGI("Enter boot animation"); @@ -2252,6 +2272,7 @@ bool SurfaceFlinger::updateLayerSnapshots(VsyncId vsyncId, LifecycleUpdate& upda } commitTransactions(); } + mustComposite |= (getTransactionFlags() & ~eTransactionFlushNeeded) || newDataLatched; return mustComposite; } @@ -2885,14 +2906,19 @@ void SurfaceFlinger::postComposition(nsecs_t callTime) { } // We avoid any reverse traversal upwards so this shouldn't be too expensive - mDrawingState.traverse([&](Layer* layer) { + traverseLegacyLayers([&](Layer* layer) { if (!layer->hasTrustedPresentationListener()) { return; } - const std::optional displayOpt = - layerStackToDisplay.get(layer->getLayerSnapshot()->outputFilter.layerStack); + const frontend::LayerSnapshot* snapshot = (mLayerLifecycleManagerEnabled) + ? mLayerSnapshotBuilder.getSnapshot(layer->sequence) + : layer->getLayerSnapshot(); + std::optional displayOpt = std::nullopt; + if (snapshot) { + displayOpt = layerStackToDisplay.get(snapshot->outputFilter.layerStack); + } const DisplayDevice* display = displayOpt.value_or(nullptr); - layer->updateTrustedPresentationState(display, layer->getLayerSnapshot(), + layer->updateTrustedPresentationState(display, snapshot, nanoseconds_to_milliseconds(callTime), false); }); } @@ -4464,6 +4490,7 @@ bool SurfaceFlinger::applyAndCommitDisplayTransactionStates( for (const auto& [_, display] : mDisplays) { mFrontEndDisplayInfos.try_emplace(display->getLayerStack(), display->getFrontEndInfo()); } + needsTraversal = true; } return needsTraversal; @@ -4643,7 +4670,7 @@ uint32_t SurfaceFlinger::setClientStateLocked(const FrameTimelineInfo& frameTime } } if (what & layer_state_t::eBackgroundColorChanged) { - if (layer->setBackgroundColor(s.color.rgb, s.bgColorAlpha, s.bgColorDataspace)) { + if (layer->setBackgroundColor(s.bgColor.rgb, s.bgColor.a, s.bgColorDataspace)) { flags |= eTraversalNeeded; } } @@ -4886,8 +4913,6 @@ uint32_t SurfaceFlinger::updateLayerCallbacksAndStats(const FrameTimelineInfo& f uint64_t transactionId) { layer_state_t& s = composerState.state; s.sanitize(permissions); - const nsecs_t latchTime = systemTime(); - bool unused; std::vector filteredListeners; for (auto& listener : s.listeners) { @@ -4940,6 +4965,12 @@ uint32_t SurfaceFlinger::updateLayerCallbacksAndStats(const FrameTimelineInfo& f sp::make(listener, callbackIds, s.surface)); } } + // TODO(b/238781169) remove after screenshot refactor, currently screenshots + // requires to read drawing state from binder thread. So we need to fix that + // before removing this. + if (what & layer_state_t::eCropChanged) { + if (layer->setCrop(s.crop)) flags |= eTraversalNeeded; + } if (what & layer_state_t::eSidebandStreamChanged) { if (layer->setSidebandStream(s.sidebandStream)) flags |= eTraversalNeeded; } @@ -4947,7 +4978,6 @@ uint32_t SurfaceFlinger::updateLayerCallbacksAndStats(const FrameTimelineInfo& f if (layer->setBuffer(composerState.externalTexture, *s.bufferData, postTime, desiredPresentTime, isAutoTimestamp, dequeueBufferTimestamp, frameTimelineInfo)) { - layer->latchBuffer(unused, latchTime); flags |= eTraversalNeeded; } mLayersWithQueuedFrames.emplace(layer); @@ -4960,11 +4990,22 @@ uint32_t SurfaceFlinger::updateLayerCallbacksAndStats(const FrameTimelineInfo& f s.trustedPresentationListener); } - const auto& snapshot = mLayerSnapshotBuilder.getSnapshot(layer->getSequence()); + const auto& requestedLayerState = mLayerLifecycleManager.getLayerFromId(layer->getSequence()); bool willPresentCurrentTransaction = - snapshot && (snapshot->hasReadyFrame || snapshot->sidebandStreamHasFrame); + requestedLayerState && requestedLayerState->hasReadyFrame(); if (layer->setTransactionCompletedListeners(callbackHandles, willPresentCurrentTransaction)) flags |= eTraversalNeeded; + + for (auto& snapshot : mLayerSnapshotBuilder.getSnapshots()) { + if (snapshot->path.isClone() || + !snapshot->changes.test(frontend::RequestedLayerState::Changes::FrameRate)) + continue; + auto it = mLegacyLayers.find(snapshot->sequence); + LOG_ALWAYS_FATAL_IF(it == mLegacyLayers.end(), "Couldnt find layer object for %s", + snapshot->getDebugString().c_str()); + it->second->setFrameRateForLayerTree(snapshot->frameRate); + } + return flags; } @@ -6922,7 +6963,7 @@ ftl::SharedFuture SurfaceFlinger::captureScreenCommon( ->schedule([=]() { bool protectedLayerFound = false; auto layers = getLayerSnapshots(); - for (auto& [layer, layerFe] : layers) { + for (auto& [_, layerFe] : layers) { protectedLayerFound |= (layerFe->mSnapshot->isVisible && layerFe->mSnapshot->hasProtectedContent); @@ -7017,7 +7058,7 @@ ftl::SharedFuture SurfaceFlinger::renderScreenImpl( ATRACE_CALL(); auto layers = getLayerSnapshots(); - for (auto& [layer, layerFE] : layers) { + for (auto& [_, layerFE] : layers) { frontend::LayerSnapshot* snapshot = layerFE->mSnapshot.get(); captureResults.capturedSecureLayers |= (snapshot->isVisible && snapshot->isSecure); captureResults.capturedHdrLayers |= isHdrLayer(*snapshot); @@ -7133,6 +7174,16 @@ ftl::SharedFuture SurfaceFlinger::renderScreenImpl( return presentFuture; } +void SurfaceFlinger::traverseLegacyLayers(const LayerVector::Visitor& visitor) const { + if (mLayerLifecycleManagerEnabled) { + for (auto& layer : mLegacyLayers) { + visitor(layer.second.get()); + } + } else { + mDrawingState.traverse(visitor); + } +} + // --------------------------------------------------------------------------- void SurfaceFlinger::State::traverse(const LayerVector::Visitor& visitor) const { @@ -7772,27 +7823,29 @@ std::vector> SurfaceFlinger::moveSnapshotsToComposit std::function>>()> SurfaceFlinger::getLayerSnapshotsForScreenshots(std::optional layerStack, uint32_t uid) { - return [this, layerStack, uid]() { + return [&, layerStack, uid]() { std::vector>> layers; - for (auto& snapshot : mLayerSnapshotBuilder.getSnapshots()) { - if (layerStack && snapshot->outputFilter.layerStack != *layerStack) { - continue; - } - if (uid != CaptureArgs::UNSET_UID && snapshot->inputInfo.ownerUid != uid) { - continue; - } - if (!snapshot->isVisible || !snapshot->hasSomethingToDraw()) { - continue; - } + mLayerSnapshotBuilder.forEachVisibleSnapshot( + [&](std::unique_ptr& snapshot) { + if (layerStack && snapshot->outputFilter.layerStack != *layerStack) { + return; + } + if (uid != CaptureArgs::UNSET_UID && snapshot->inputInfo.ownerUid != uid) { + return; + } + if (!snapshot->hasSomethingToDraw()) { + return; + } - auto it = mLegacyLayers.find(snapshot->sequence); - LOG_ALWAYS_FATAL_IF(it == mLegacyLayers.end(), "Couldnt find layer object for %s", - snapshot->getDebugString().c_str()); - auto& legacyLayer = it->second; - sp layerFE = getFactory().createLayerFE(legacyLayer->getName()); - layerFE->mSnapshot = std::make_unique(*snapshot); - layers.emplace_back(legacyLayer.get(), std::move(layerFE)); - } + auto it = mLegacyLayers.find(snapshot->sequence); + LOG_ALWAYS_FATAL_IF(it == mLegacyLayers.end(), + "Couldnt find layer object for %s", + snapshot->getDebugString().c_str()); + Layer* legacyLayer = (it == mLegacyLayers.end()) ? nullptr : it->second.get(); + sp layerFE = getFactory().createLayerFE(snapshot->name); + layerFE->mSnapshot = std::make_unique(*snapshot); + layers.emplace_back(legacyLayer, std::move(layerFE)); + }); return layers; }; @@ -7802,11 +7855,13 @@ std::function>>()> SurfaceFlinger::getLayerSnapshotsForScreenshots(uint32_t rootLayerId, uint32_t uid, std::unordered_set excludeLayerIds, bool childrenOnly, const FloatRect& parentCrop) { - return [this, excludeLayerIds = std::move(excludeLayerIds), uid, rootLayerId, childrenOnly, + return [&, rootLayerId, uid, excludeLayerIds = std::move(excludeLayerIds), childrenOnly, parentCrop]() { + auto root = mLayerHierarchyBuilder.getPartialHierarchy(rootLayerId, childrenOnly); frontend::LayerSnapshotBuilder::Args - args{.root = mLayerHierarchyBuilder.getPartialHierarchy(rootLayerId, childrenOnly), + args{.root = root, .layerLifecycleManager = mLayerLifecycleManager, + .forceUpdate = frontend::LayerSnapshotBuilder::ForceUpdateFlags::HIERARCHY, .displays = mFrontEndDisplayInfos, .displayChanges = true, .globalShadowSettings = mDrawingState.globalShadowSettings, diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index b41f414f62..adba9b86f9 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -1126,6 +1126,7 @@ private: ui::Rotation getPhysicalDisplayOrientation(DisplayId, bool isPrimary) const REQUIRES(mStateLock); + void traverseLegacyLayers(const LayerVector::Visitor& visitor) const; sp mStartPropertySetThread; surfaceflinger::Factory& mFactory; diff --git a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp index 2f464873ea..e0ef8a53cf 100644 --- a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp +++ b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp @@ -220,12 +220,12 @@ proto::LayerState TransactionProtoParser::toProto(const layer_state_t& layer) { } } if (layer.what & layer_state_t::eBackgroundColorChanged) { - proto.set_bg_color_alpha(layer.bgColorAlpha); + proto.set_bg_color_alpha(layer.bgColor.a); proto.set_bg_color_dataspace(static_cast(layer.bgColorDataspace)); proto::LayerState_Color3* colorProto = proto.mutable_color(); - colorProto->set_r(layer.color.r); - colorProto->set_g(layer.color.g); - colorProto->set_b(layer.color.b); + colorProto->set_r(layer.bgColor.r); + colorProto->set_g(layer.bgColor.g); + colorProto->set_b(layer.bgColor.b); } if (layer.what & layer_state_t::eColorSpaceAgnosticChanged) { proto.set_color_space_agnostic(layer.colorSpaceAgnostic); @@ -501,12 +501,12 @@ void TransactionProtoParser::fromProto(const proto::LayerState& proto, layer_sta layer.windowInfoHandle = sp::make(inputInfo); } if (proto.what() & layer_state_t::eBackgroundColorChanged) { - layer.bgColorAlpha = proto.bg_color_alpha(); + layer.bgColor.a = proto.bg_color_alpha(); layer.bgColorDataspace = static_cast(proto.bg_color_dataspace()); const proto::LayerState_Color3& colorProto = proto.color(); - layer.color.r = colorProto.r(); - layer.color.g = colorProto.g(); - layer.color.b = colorProto.b(); + layer.bgColor.r = colorProto.r(); + layer.bgColor.g = colorProto.g(); + layer.bgColor.b = colorProto.b(); } if (proto.what() & layer_state_t::eColorSpaceAgnosticChanged) { layer.colorSpaceAgnostic = proto.color_space_agnostic(); diff --git a/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp index bf7cae9091..0b8c51ec1d 100644 --- a/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp +++ b/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp @@ -544,6 +544,7 @@ void LayerRenderTypeTransactionTest::setBackgroundColorHelper(uint32_t layerType .apply(); { + SCOPED_TRACE("final color"); auto shot = screenshot(); shot->expectColor(Rect(0, 0, width, height), finalColor); shot->expectBorder(Rect(0, 0, width, height), Color::BLACK); diff --git a/services/surfaceflinger/tests/MirrorLayer_test.cpp b/services/surfaceflinger/tests/MirrorLayer_test.cpp index e69db7c167..0ea0824732 100644 --- a/services/surfaceflinger/tests/MirrorLayer_test.cpp +++ b/services/surfaceflinger/tests/MirrorLayer_test.cpp @@ -18,6 +18,7 @@ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wconversion" +#include #include #include "LayerTransactionTest.h" #include "utils/TransactionUtils.h" @@ -119,15 +120,20 @@ TEST_F(MirrorLayerTest, MirrorColorLayer) { shot->expectColor(Rect(750, 750, 950, 950), Color::BLACK); } - // Remove child layer + if (base::GetBoolProperty("debug.sf.enable_legacy_frontend", true)) { + GTEST_SKIP() << "Skipping test because mirroring behavior changes with legacy frontend"; + } + + // Remove child layer and verify we can still mirror the layer when + // its offscreen. Transaction().reparent(mChildLayer, nullptr).apply(); { SCOPED_TRACE("Removed Child Layer"); auto shot = screenshot(); // Grandchild mirror - shot->expectColor(Rect(550, 550, 750, 750), Color::RED); + shot->expectColor(Rect(550, 550, 750, 750), Color::BLACK); // Child mirror - shot->expectColor(Rect(750, 750, 950, 950), Color::RED); + shot->expectColor(Rect(750, 750, 950, 950), Color::BLACK); } // Add grandchild layer to offscreen layer @@ -136,9 +142,9 @@ TEST_F(MirrorLayerTest, MirrorColorLayer) { SCOPED_TRACE("Added Grandchild Layer"); auto shot = screenshot(); // Grandchild mirror - shot->expectColor(Rect(550, 550, 750, 750), Color::RED); + shot->expectColor(Rect(550, 550, 750, 750), Color::WHITE); // Child mirror - shot->expectColor(Rect(750, 750, 950, 950), Color::RED); + shot->expectColor(Rect(750, 750, 950, 950), Color::BLACK); } // Add child layer diff --git a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.cpp b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.cpp index 763426a9f8..19164049a7 100644 --- a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.cpp @@ -437,10 +437,11 @@ TEST_F(LayerHierarchyTest, backgroundLayersAreBehindParentLayer) { updateBackgroundColor(1, 0.5); UPDATE_AND_VERIFY(hierarchyBuilder); - - std::vector expectedTraversalPath = {1, 1222, 11, 111, 12, 121, 122, 1221, 13, 2}; + auto bgLayerId = LayerCreationArgs::getInternalLayerId(1); + std::vector expectedTraversalPath = {1, bgLayerId, 11, 111, 12, + 121, 122, 1221, 13, 2}; EXPECT_EQ(getTraversalPath(hierarchyBuilder.getHierarchy()), expectedTraversalPath); - expectedTraversalPath = {1222, 1, 11, 111, 12, 121, 122, 1221, 13, 2}; + expectedTraversalPath = {bgLayerId, 1, 11, 111, 12, 121, 122, 1221, 13, 2}; EXPECT_EQ(getTraversalPathInZOrder(hierarchyBuilder.getHierarchy()), expectedTraversalPath); expectedTraversalPath = {}; EXPECT_EQ(getTraversalPath(hierarchyBuilder.getOffscreenHierarchy()), expectedTraversalPath); diff --git a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h index 852cb91b2c..cdcc6f4eb2 100644 --- a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h +++ b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h @@ -172,7 +172,7 @@ protected: transactions.emplace_back(); transactions.back().states.push_back({}); transactions.back().states.front().state.what = layer_state_t::eBackgroundColorChanged; - transactions.back().states.front().state.bgColorAlpha = alpha; + transactions.back().states.front().state.bgColor.a = alpha; transactions.back().states.front().state.surface = mHandles[id]; mLifecycleManager.applyTransactions(transactions); } diff --git a/services/surfaceflinger/tests/unittests/LayerLifecycleManagerTest.cpp b/services/surfaceflinger/tests/unittests/LayerLifecycleManagerTest.cpp index 89440a689c..99c1d23c2b 100644 --- a/services/surfaceflinger/tests/unittests/LayerLifecycleManagerTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerLifecycleManagerTest.cpp @@ -372,7 +372,7 @@ TEST_F(LayerLifecycleManagerTest, canAddBackgroundLayer) { std::vector transactions; transactions.emplace_back(); transactions.back().states.push_back({}); - transactions.back().states.front().state.bgColorAlpha = 0.5; + transactions.back().states.front().state.bgColor.a = 0.5; transactions.back().states.front().state.what = layer_state_t::eBackgroundColorChanged; sp handle = sp::make(1u); transactions.back().states.front().state.surface = handle; @@ -383,9 +383,10 @@ TEST_F(LayerLifecycleManagerTest, canAddBackgroundLayer) { EXPECT_TRUE(lifecycleManager.getGlobalChanges().test(RequestedLayerState::Changes::Hierarchy)); lifecycleManager.commitChanges(); - listener->expectLayersAdded({1, 2}); + auto bgLayerId = LayerCreationArgs::getInternalLayerId(1); + listener->expectLayersAdded({1, bgLayerId}); listener->expectLayersDestroyed({}); - EXPECT_EQ(getRequestedLayerState(lifecycleManager, 2)->color.a, 0.5_hf); + EXPECT_EQ(getRequestedLayerState(lifecycleManager, bgLayerId)->color.a, 0.5_hf); } TEST_F(LayerLifecycleManagerTest, canDestroyBackgroundLayer) { @@ -400,13 +401,13 @@ TEST_F(LayerLifecycleManagerTest, canDestroyBackgroundLayer) { std::vector transactions; transactions.emplace_back(); transactions.back().states.push_back({}); - transactions.back().states.front().state.bgColorAlpha = 0.5; + transactions.back().states.front().state.bgColor.a = 0.5; transactions.back().states.front().state.what = layer_state_t::eBackgroundColorChanged; sp handle = sp::make(1u); transactions.back().states.front().state.surface = handle; transactions.emplace_back(); transactions.back().states.push_back({}); - transactions.back().states.front().state.bgColorAlpha = 0; + transactions.back().states.front().state.bgColor.a = 0; transactions.back().states.front().state.what = layer_state_t::eBackgroundColorChanged; transactions.back().states.front().state.surface = handle; @@ -417,8 +418,9 @@ TEST_F(LayerLifecycleManagerTest, canDestroyBackgroundLayer) { EXPECT_TRUE(lifecycleManager.getGlobalChanges().test(RequestedLayerState::Changes::Hierarchy)); lifecycleManager.commitChanges(); - listener->expectLayersAdded({1, 2}); - listener->expectLayersDestroyed({2}); + auto bgLayerId = LayerCreationArgs::getInternalLayerId(1); + listener->expectLayersAdded({1, bgLayerId}); + listener->expectLayersDestroyed({bgLayerId}); } TEST_F(LayerLifecycleManagerTest, onParentDestroyDestroysBackgroundLayer) { @@ -433,7 +435,7 @@ TEST_F(LayerLifecycleManagerTest, onParentDestroyDestroysBackgroundLayer) { std::vector transactions; transactions.emplace_back(); transactions.back().states.push_back({}); - transactions.back().states.front().state.bgColorAlpha = 0.5; + transactions.back().states.front().state.bgColor.a = 0.5; transactions.back().states.front().state.what = layer_state_t::eBackgroundColorChanged; sp handle = sp::make(1u); transactions.back().states.front().state.surface = handle; @@ -446,8 +448,9 @@ TEST_F(LayerLifecycleManagerTest, onParentDestroyDestroysBackgroundLayer) { EXPECT_TRUE(lifecycleManager.getGlobalChanges().test(RequestedLayerState::Changes::Hierarchy)); lifecycleManager.commitChanges(); - listener->expectLayersAdded({1, 2}); - listener->expectLayersDestroyed({1, 2}); + auto bgLayerId = LayerCreationArgs::getInternalLayerId(1); + listener->expectLayersAdded({1, bgLayerId}); + listener->expectLayersDestroyed({1, bgLayerId}); } } // namespace android::surfaceflinger::frontend -- cgit v1.2.3-59-g8ed1b From 963049b5ff733bc35933d5c565a35f2f7af09f88 Mon Sep 17 00:00:00 2001 From: Sally Qi Date: Thu, 23 Mar 2023 14:06:21 -0700 Subject: Rename Sdr/Hdr to Hdr/Sdr internally to get avoid of confusion. Bug: 267350616 Test: builds Change-Id: I75bb485f01ae2358c77133767f01cb63f8eda6f1 --- libs/gui/LayerState.cpp | 16 ++++++++-------- libs/gui/SurfaceComposerClient.cpp | 4 ++-- libs/gui/include/gui/LayerState.h | 4 ++-- .../compositionengine/LayerFECompositionState.h | 4 ++-- .../compositionengine/impl/planner/LayerState.h | 2 +- .../src/LayerFECompositionState.cpp | 6 +++--- .../CompositionEngine/src/OutputLayer.cpp | 4 ++-- .../tests/planner/CachedSetTest.cpp | 2 +- .../FrontEnd/LayerSnapshotBuilder.cpp | 4 ++-- .../FrontEnd/RequestedLayerState.cpp | 4 ++-- services/surfaceflinger/Layer.cpp | 22 +++++++++++----------- services/surfaceflinger/Layer.h | 10 +++++----- services/surfaceflinger/SurfaceFlinger.cpp | 10 ++++------ 13 files changed, 45 insertions(+), 47 deletions(-) (limited to 'libs/gui/LayerState.cpp') diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index b391337d1d..196949682d 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -190,8 +190,8 @@ status_t layer_state_t::write(Parcel& output) const } SAFE_PARCEL(output.writeParcelable, trustedPresentationThresholds); SAFE_PARCEL(output.writeParcelable, trustedPresentationListener); - SAFE_PARCEL(output.writeFloat, currentSdrHdrRatio); - SAFE_PARCEL(output.writeFloat, desiredSdrHdrRatio); + SAFE_PARCEL(output.writeFloat, currentHdrSdrRatio); + SAFE_PARCEL(output.writeFloat, desiredHdrSdrRatio); SAFE_PARCEL(output.writeInt32, static_cast(cachingHint)) return NO_ERROR; } @@ -335,9 +335,9 @@ status_t layer_state_t::read(const Parcel& input) SAFE_PARCEL(input.readParcelable, &trustedPresentationListener); SAFE_PARCEL(input.readFloat, &tmpFloat); - currentSdrHdrRatio = tmpFloat; + currentHdrSdrRatio = tmpFloat; SAFE_PARCEL(input.readFloat, &tmpFloat); - desiredSdrHdrRatio = tmpFloat; + desiredHdrSdrRatio = tmpFloat; int32_t tmpInt32; SAFE_PARCEL(input.readInt32, &tmpInt32); @@ -592,8 +592,8 @@ void layer_state_t::merge(const layer_state_t& other) { } if (other.what & eExtendedRangeBrightnessChanged) { what |= eExtendedRangeBrightnessChanged; - desiredSdrHdrRatio = other.desiredSdrHdrRatio; - currentSdrHdrRatio = other.currentSdrHdrRatio; + desiredHdrSdrRatio = other.desiredHdrSdrRatio; + currentHdrSdrRatio = other.currentHdrSdrRatio; } if (other.what & eCachingHintChanged) { what |= eCachingHintChanged; @@ -747,8 +747,8 @@ uint64_t layer_state_t::diff(const layer_state_t& other) const { CHECK_DIFF(diff, eCropChanged, other, crop); if (other.what & eBufferChanged) diff |= eBufferChanged; CHECK_DIFF(diff, eDataspaceChanged, other, dataspace); - CHECK_DIFF2(diff, eExtendedRangeBrightnessChanged, other, currentSdrHdrRatio, - desiredSdrHdrRatio); + CHECK_DIFF2(diff, eExtendedRangeBrightnessChanged, other, currentHdrSdrRatio, + desiredHdrSdrRatio); CHECK_DIFF(diff, eCachingHintChanged, other, cachingHint); CHECK_DIFF(diff, eHdrMetadataChanged, other, hdrMetadata); if (other.what & eSurfaceDamageRegionChanged && diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 2f5830d362..7700aa4044 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1723,8 +1723,8 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setExten return *this; } s->what |= layer_state_t::eExtendedRangeBrightnessChanged; - s->currentSdrHdrRatio = currentBufferRatio; - s->desiredSdrHdrRatio = desiredRatio; + s->currentHdrSdrRatio = currentBufferRatio; + s->desiredHdrSdrRatio = desiredRatio; registerSurfaceControlForCallback(sc); return *this; diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index 6e3be5cef8..5c88a07ba8 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -389,8 +389,8 @@ struct layer_state_t { gui::DropInputMode dropInputMode; bool dimmingEnabled; - float currentSdrHdrRatio = 1.f; - float desiredSdrHdrRatio = 1.f; + float currentHdrSdrRatio = 1.f; + float desiredHdrSdrRatio = 1.f; gui::CachingHint cachingHint = gui::CachingHint::Enabled; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h index eae5871477..35ca3a58d9 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h @@ -210,8 +210,8 @@ struct LayerFECompositionState { // The dimming flag bool dimmingEnabled{true}; - float currentSdrHdrRatio = 1.f; - float desiredSdrHdrRatio = 1.f; + float currentHdrSdrRatio = 1.f; + float desiredHdrSdrRatio = 1.f; gui::CachingHint cachingHint = gui::CachingHint::Enabled; virtual ~LayerFECompositionState(); diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h index ee9e646c1f..ce2b96fc2b 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h @@ -248,7 +248,7 @@ public: ui::Dataspace getDataspace() const { return mOutputDataspace.get(); } float getHdrSdrRatio() const { - return getOutputLayer()->getLayerFE().getCompositionState()->currentSdrHdrRatio; + return getOutputLayer()->getLayerFE().getCompositionState()->currentHdrSdrRatio; }; wp getBuffer() const { return mBuffer.get(); } diff --git a/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp index 615d04b460..426cc57db8 100644 --- a/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp +++ b/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp @@ -121,9 +121,9 @@ void LayerFECompositionState::dump(std::string& out) const { dumpVal(out, "dataspace", toString(dataspace), dataspace); dumpVal(out, "hdr metadata types", hdrMetadata.validTypes); dumpVal(out, "dimming enabled", dimmingEnabled); - if (currentSdrHdrRatio > 1.01f || desiredSdrHdrRatio > 1.01f) { - dumpVal(out, "current sdr/hdr ratio", currentSdrHdrRatio); - dumpVal(out, "desired sdr/hdr ratio", desiredSdrHdrRatio); + if (currentHdrSdrRatio > 1.01f || desiredHdrSdrRatio > 1.01f) { + dumpVal(out, "current hdr/sdr ratio", currentHdrSdrRatio); + dumpVal(out, "desired hdr/sdr ratio", desiredHdrSdrRatio); } dumpVal(out, "colorTransform", colorTransform); dumpVal(out, "caching hint", toString(cachingHint)); diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp index 1b86cd376a..0ac0ecb727 100644 --- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp +++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp @@ -344,8 +344,8 @@ void OutputLayer::updateCompositionState( // RANGE_EXTENDED can "self-promote" to HDR, but is still rendered for a particular // range that we may need to re-adjust to the current display conditions if ((state.dataspace & HAL_DATASPACE_RANGE_MASK) == HAL_DATASPACE_RANGE_EXTENDED && - layerFEState->currentSdrHdrRatio > 1.01f) { - layerBrightnessNits *= layerFEState->currentSdrHdrRatio; + layerFEState->currentHdrSdrRatio > 1.01f) { + layerBrightnessNits *= layerFEState->currentHdrSdrRatio; } state.dimmingRatio = std::clamp(layerBrightnessNits / getOutput().getState().displayBrightnessNits, 0.f, diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp index 1f7fb93c6b..bd030d090f 100644 --- a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp @@ -667,7 +667,7 @@ TEST_F(CachedSetTest, holePunch_requiresNonHdrWithExtendedBrightness) { ui::Dataspace::TRANSFER_SRGB | ui::Dataspace::RANGE_EXTENDED); mTestLayers[0]->outputLayerCompositionState.dataspace = dataspace; - mTestLayers[0]->layerFECompositionState.currentSdrHdrRatio = 5.f; + mTestLayers[0]->layerFECompositionState.currentHdrSdrRatio = 5.f; mTestLayers[0]->layerState->update(&mTestLayers[0]->outputLayer); CachedSet::Layer& layer = *mTestLayers[0]->cachedSetLayer.get(); diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp index a16de1bcfb..70670dd022 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp +++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp @@ -707,8 +707,8 @@ void LayerSnapshotBuilder::updateSnapshot(LayerSnapshot& snapshot, const Args& a snapshot.sidebandStream = requested.sidebandStream; snapshot.transparentRegionHint = requested.transparentRegion; snapshot.color.rgb = requested.getColor().rgb; - snapshot.currentSdrHdrRatio = requested.currentSdrHdrRatio; - snapshot.desiredSdrHdrRatio = requested.desiredSdrHdrRatio; + snapshot.currentHdrSdrRatio = requested.currentHdrSdrRatio; + snapshot.desiredHdrSdrRatio = requested.desiredHdrSdrRatio; } if (snapshot.isHiddenByPolicyFromParent && diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp index a5fdaf4fe3..1f670c81df 100644 --- a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp +++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp @@ -100,8 +100,8 @@ RequestedLayerState::RequestedLayerState(const LayerCreationArgs& args) layerStack = ui::DEFAULT_LAYER_STACK; transformToDisplayInverse = false; dataspace = ui::Dataspace::UNKNOWN; - desiredSdrHdrRatio = 1.f; - currentSdrHdrRatio = 1.f; + desiredHdrSdrRatio = 1.f; + currentHdrSdrRatio = 1.f; dataspaceRequested = false; hdrMetadata.validTypes = 0; surfaceDamageRegion = Region::INVALID_REGION; diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 95213718e5..be021510df 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -639,8 +639,8 @@ void Layer::preparePerFrameCompositionState() { snapshot->surfaceDamage = surfaceDamageRegion; snapshot->hasProtectedContent = isProtected(); snapshot->dimmingEnabled = isDimmingEnabled(); - snapshot->currentSdrHdrRatio = getCurrentSdrHdrRatio(); - snapshot->desiredSdrHdrRatio = getDesiredSdrHdrRatio(); + snapshot->currentHdrSdrRatio = getCurrentHdrSdrRatio(); + snapshot->desiredHdrSdrRatio = getDesiredHdrSdrRatio(); snapshot->cachingHint = getCachingHint(); const bool usesRoundedCorners = hasRoundedCorners(); @@ -3141,11 +3141,11 @@ bool Layer::setDataspace(ui::Dataspace dataspace) { } bool Layer::setExtendedRangeBrightness(float currentBufferRatio, float desiredRatio) { - if (mDrawingState.currentSdrHdrRatio == currentBufferRatio && - mDrawingState.desiredSdrHdrRatio == desiredRatio) + if (mDrawingState.currentHdrSdrRatio == currentBufferRatio && + mDrawingState.desiredHdrSdrRatio == desiredRatio) return false; - mDrawingState.currentSdrHdrRatio = currentBufferRatio; - mDrawingState.desiredSdrHdrRatio = desiredRatio; + mDrawingState.currentHdrSdrRatio = currentBufferRatio; + mDrawingState.desiredHdrSdrRatio = desiredRatio; mDrawingState.modified = true; setTransactionFlags(eTransactionNeeded); return true; @@ -3400,8 +3400,8 @@ void Layer::gatherBufferInfo() { if (lastDataspace != mBufferInfo.mDataspace) { mFlinger->mHdrLayerInfoChanged = true; } - if (mBufferInfo.mDesiredSdrHdrRatio != mDrawingState.desiredSdrHdrRatio) { - mBufferInfo.mDesiredSdrHdrRatio = mDrawingState.desiredSdrHdrRatio; + if (mBufferInfo.mDesiredHdrSdrRatio != mDrawingState.desiredHdrSdrRatio) { + mBufferInfo.mDesiredHdrSdrRatio = mDrawingState.desiredHdrSdrRatio; mFlinger->mHdrLayerInfoChanged = true; } mBufferInfo.mCrop = computeBufferCrop(mDrawingState); @@ -3661,9 +3661,9 @@ bool Layer::simpleBufferUpdate(const layer_state_t& s) const { } if (s.what & layer_state_t::eExtendedRangeBrightnessChanged) { - if (mDrawingState.currentSdrHdrRatio != s.currentSdrHdrRatio || - mDrawingState.desiredSdrHdrRatio != s.desiredSdrHdrRatio) { - ALOGV("%s: false [eDimmingEnabledChanged changed]", __func__); + if (mDrawingState.currentHdrSdrRatio != s.currentHdrSdrRatio || + mDrawingState.desiredHdrSdrRatio != s.desiredHdrSdrRatio) { + ALOGV("%s: false [eExtendedRangeBrightnessChanged changed]", __func__); return false; } } diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index f7e1969ec0..ade3e20dec 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -225,8 +225,8 @@ public: gui::DropInputMode dropInputMode; bool autoRefresh = false; bool dimmingEnabled = true; - float currentSdrHdrRatio = 1.f; - float desiredSdrHdrRatio = 1.f; + float currentHdrSdrRatio = 1.f; + float desiredHdrSdrRatio = 1.f; gui::CachingHint cachingHint = gui::CachingHint::Enabled; int64_t latchedVsyncId = 0; }; @@ -296,8 +296,8 @@ public: virtual bool hasColorTransform() const; virtual bool isColorSpaceAgnostic() const { return mDrawingState.colorSpaceAgnostic; } virtual bool isDimmingEnabled() const { return getDrawingState().dimmingEnabled; } - float getDesiredSdrHdrRatio() const { return getDrawingState().desiredSdrHdrRatio; } - float getCurrentSdrHdrRatio() const { return getDrawingState().currentSdrHdrRatio; } + float getDesiredHdrSdrRatio() const { return getDrawingState().desiredHdrSdrRatio; } + float getCurrentHdrSdrRatio() const { return getDrawingState().currentHdrSdrRatio; } gui::CachingHint getCachingHint() const { return getDrawingState().cachingHint; } bool setTransform(uint32_t /*transform*/); @@ -519,7 +519,7 @@ public: uint64_t mFrameNumber; bool mFrameLatencyNeeded{false}; - float mDesiredSdrHdrRatio = 1.f; + float mDesiredHdrSdrRatio = 1.f; }; BufferInfo mBufferInfo; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 639ea27adc..309b90a04d 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2763,7 +2763,7 @@ bool SurfaceFlinger::isHdrLayer(const frontend::LayerSnapshot& snapshot) const { // RANGE_EXTENDED layers may identify themselves as being "HDR" via a desired sdr/hdr ratio if ((snapshot.dataspace & (int32_t)Dataspace::RANGE_MASK) == (int32_t)Dataspace::RANGE_EXTENDED && - snapshot.desiredSdrHdrRatio > 1.01f) { + snapshot.desiredHdrSdrRatio > 1.01f) { return true; } return false; @@ -2900,11 +2900,9 @@ void SurfaceFlinger::postComposition(nsecs_t callTime) { const auto* outputLayer = compositionDisplay->getOutputLayerForLayer(layerFe); if (outputLayer) { - // TODO(b/267350616): Rename SdrHdrRatio -> HdrSdrRatio - // everywhere - const float desiredHdrSdrRatio = snapshot.desiredSdrHdrRatio <= 1.f + const float desiredHdrSdrRatio = snapshot.desiredHdrSdrRatio <= 1.f ? std::numeric_limits::infinity() - : snapshot.desiredSdrHdrRatio; + : snapshot.desiredHdrSdrRatio; info.mergeDesiredRatio(desiredHdrSdrRatio); info.numberOfHdrLayers++; const auto displayFrame = outputLayer->getState().displayFrame; @@ -4931,7 +4929,7 @@ uint32_t SurfaceFlinger::setClientStateLocked(const FrameTimelineInfo& frameTime if (layer->setDimmingEnabled(s.dimmingEnabled)) flags |= eTraversalNeeded; } if (what & layer_state_t::eExtendedRangeBrightnessChanged) { - if (layer->setExtendedRangeBrightness(s.currentSdrHdrRatio, s.desiredSdrHdrRatio)) { + if (layer->setExtendedRangeBrightness(s.currentHdrSdrRatio, s.desiredHdrSdrRatio)) { flags |= eTraversalNeeded; } } -- cgit v1.2.3-59-g8ed1b From 0284463f01bad248b39fce18b44a62551c91a070 Mon Sep 17 00:00:00 2001 From: Ajinkya Chalke Date: Wed, 1 Mar 2023 12:10:14 +0000 Subject: Move exclude layer to CaptureArgs. Test: atest ScreenCaptureTest ScreenCaptureChildOnlyTest Bug: 267324693 Change-Id: I6ab421e2f9e5bc0ab1422d88ddf2628776347a6f --- libs/gui/LayerState.cpp | 27 +++++---- libs/gui/include/gui/DisplayCaptureArgs.h | 4 ++ libs/gui/include/gui/LayerCaptureArgs.h | 3 - services/surfaceflinger/RegionSamplingThread.cpp | 3 +- services/surfaceflinger/SurfaceFlinger.cpp | 70 ++++++++++++++++++++-- services/surfaceflinger/SurfaceFlinger.h | 7 ++- .../surfaceflinger/tests/ScreenCapture_test.cpp | 8 +++ .../tests/unittests/CompositionTest.cpp | 2 +- .../tests/unittests/TestableSurfaceFlinger.h | 4 +- 9 files changed, 104 insertions(+), 24 deletions(-) (limited to 'libs/gui/LayerState.cpp') diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index b391337d1d..cf171dcec9 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -897,6 +897,11 @@ status_t CaptureArgs::writeToParcel(Parcel* output) const { SAFE_PARCEL(output->writeInt32, static_cast(dataspace)); SAFE_PARCEL(output->writeBool, allowProtected); SAFE_PARCEL(output->writeBool, grayscale); + + SAFE_PARCEL(output->writeInt32, excludeHandles.size()); + for (auto& excludeHandle : excludeHandles) { + SAFE_PARCEL(output->writeStrongBinder, excludeHandle); + } return NO_ERROR; } @@ -913,6 +918,15 @@ status_t CaptureArgs::readFromParcel(const Parcel* input) { dataspace = static_cast(value); SAFE_PARCEL(input->readBool, &allowProtected); SAFE_PARCEL(input->readBool, &grayscale); + + int32_t numExcludeHandles = 0; + SAFE_PARCEL_READ_SIZE(input->readInt32, &numExcludeHandles, input->dataSize()); + excludeHandles.reserve(numExcludeHandles); + for (int i = 0; i < numExcludeHandles; i++) { + sp binder; + SAFE_PARCEL(input->readStrongBinder, &binder); + excludeHandles.emplace(binder); + } return NO_ERROR; } @@ -940,10 +954,6 @@ status_t LayerCaptureArgs::writeToParcel(Parcel* output) const { SAFE_PARCEL(CaptureArgs::writeToParcel, output); SAFE_PARCEL(output->writeStrongBinder, layerHandle); - SAFE_PARCEL(output->writeInt32, excludeHandles.size()); - for (auto el : excludeHandles) { - SAFE_PARCEL(output->writeStrongBinder, el); - } SAFE_PARCEL(output->writeBool, childrenOnly); return NO_ERROR; } @@ -953,15 +963,6 @@ status_t LayerCaptureArgs::readFromParcel(const Parcel* input) { SAFE_PARCEL(input->readStrongBinder, &layerHandle); - int32_t numExcludeHandles = 0; - SAFE_PARCEL_READ_SIZE(input->readInt32, &numExcludeHandles, input->dataSize()); - excludeHandles.reserve(numExcludeHandles); - for (int i = 0; i < numExcludeHandles; i++) { - sp binder; - SAFE_PARCEL(input->readStrongBinder, &binder); - excludeHandles.emplace(binder); - } - SAFE_PARCEL(input->readBool, &childrenOnly); return NO_ERROR; } diff --git a/libs/gui/include/gui/DisplayCaptureArgs.h b/libs/gui/include/gui/DisplayCaptureArgs.h index c826c17d2c..5c794aea37 100644 --- a/libs/gui/include/gui/DisplayCaptureArgs.h +++ b/libs/gui/include/gui/DisplayCaptureArgs.h @@ -22,9 +22,11 @@ #include #include #include +#include #include #include #include +#include namespace android::gui { @@ -55,6 +57,8 @@ struct CaptureArgs : public Parcelable { bool grayscale = false; + std::unordered_set, SpHash> excludeHandles; + virtual status_t writeToParcel(Parcel* output) const; virtual status_t readFromParcel(const Parcel* input); }; diff --git a/libs/gui/include/gui/LayerCaptureArgs.h b/libs/gui/include/gui/LayerCaptureArgs.h index 05ff9d5b7b..fae2bcc787 100644 --- a/libs/gui/include/gui/LayerCaptureArgs.h +++ b/libs/gui/include/gui/LayerCaptureArgs.h @@ -20,14 +20,11 @@ #include #include -#include -#include namespace android::gui { struct LayerCaptureArgs : CaptureArgs { sp layerHandle; - std::unordered_set, SpHash> excludeHandles; bool childrenOnly{false}; status_t writeToParcel(Parcel* output) const override; diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp index 327ca3f0aa..531d277ffc 100644 --- a/services/surfaceflinger/RegionSamplingThread.cpp +++ b/services/surfaceflinger/RegionSamplingThread.cpp @@ -347,7 +347,8 @@ void RegionSamplingThread::captureSample() { } visitor(layer); }; - mFlinger.traverseLayersInLayerStack(layerStack, CaptureArgs::UNSET_UID, filterVisitor); + mFlinger.traverseLayersInLayerStack(layerStack, CaptureArgs::UNSET_UID, {}, + filterVisitor); }; getLayerSnapshots = RenderArea::fromTraverseLayersLambda(traverseLayers); } diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 076c6839c6..791b42512c 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -6888,6 +6888,7 @@ status_t SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args, wp displayWeak; ui::LayerStack layerStack; ui::Size reqSize(args.width, args.height); + std::unordered_set excludeLayerIds; ui::Dataspace dataspace; { Mutex::Autolock lock(mStateLock); @@ -6901,6 +6902,16 @@ status_t SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args, reqSize = display->getLayerStackSpaceRect().getSize(); } + for (const auto& handle : args.excludeHandles) { + uint32_t excludeLayer = LayerHandle::getLayerId(handle); + if (excludeLayer != UNASSIGNED_LAYER_ID) { + excludeLayerIds.emplace(excludeLayer); + } else { + ALOGW("Invalid layer handle passed as excludeLayer to captureDisplay"); + return NAME_NOT_FOUND; + } + } + // Allow the caller to specify a dataspace regardless of the display's color mode, e.g. if // it wants sRGB regardless of the display's wide color mode. dataspace = args.dataspace == ui::Dataspace::UNKNOWN @@ -6916,10 +6927,11 @@ status_t SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args, GetLayerSnapshotsFunction getLayerSnapshots; if (mLayerLifecycleManagerEnabled) { getLayerSnapshots = - getLayerSnapshotsForScreenshots(layerStack, args.uid, /*snapshotFilterFn=*/nullptr); + getLayerSnapshotsForScreenshots(layerStack, args.uid, std::move(excludeLayerIds)); } else { - auto traverseLayers = [this, args, layerStack](const LayerVector::Visitor& visitor) { - traverseLayersInLayerStack(layerStack, args.uid, visitor); + auto traverseLayers = [this, args, excludeLayerIds, + layerStack](const LayerVector::Visitor& visitor) { + traverseLayersInLayerStack(layerStack, args.uid, std::move(excludeLayerIds), visitor); }; getLayerSnapshots = RenderArea::fromTraverseLayersLambda(traverseLayers); } @@ -6962,7 +6974,7 @@ status_t SurfaceFlinger::captureDisplay(DisplayId displayId, /*snapshotFilterFn=*/nullptr); } else { auto traverseLayers = [this, layerStack](const LayerVector::Visitor& visitor) { - traverseLayersInLayerStack(layerStack, CaptureArgs::UNSET_UID, visitor); + traverseLayersInLayerStack(layerStack, CaptureArgs::UNSET_UID, {}, visitor); }; getLayerSnapshots = RenderArea::fromTraverseLayersLambda(traverseLayers); } @@ -7386,6 +7398,7 @@ void SurfaceFlinger::State::traverseInReverseZOrder(const LayerVector::Visitor& } void SurfaceFlinger::traverseLayersInLayerStack(ui::LayerStack layerStack, const int32_t uid, + std::unordered_set excludeLayerIds, const LayerVector::Visitor& visitor) { // We loop through the first level of layers without traversing, // as we need to determine which layers belong to the requested display. @@ -7404,6 +7417,17 @@ void SurfaceFlinger::traverseLayersInLayerStack(ui::LayerStack layerStack, const if (uid != CaptureArgs::UNSET_UID && layer->getOwnerUid() != uid) { return; } + + if (!excludeLayerIds.empty()) { + auto p = sp::fromExisting(layer); + while (p != nullptr) { + if (excludeLayerIds.count(p->sequence) != 0) { + return; + } + p = p->getParent(); + } + } + visitor(layer); }); } @@ -8058,6 +8082,44 @@ SurfaceFlinger::getLayerSnapshotsForScreenshots( }; } +std::function>>()> +SurfaceFlinger::getLayerSnapshotsForScreenshots(std::optional layerStack, + uint32_t uid, + std::unordered_set excludeLayerIds) { + return [&, layerStack, uid, excludeLayerIds = std::move(excludeLayerIds)]() { + if (excludeLayerIds.empty()) { + auto getLayerSnapshotsFn = + getLayerSnapshotsForScreenshots(layerStack, uid, /*snapshotFilterFn=*/nullptr); + std::vector>> layers = getLayerSnapshotsFn(); + return layers; + } + + frontend::LayerSnapshotBuilder::Args + args{.root = mLayerHierarchyBuilder.getHierarchy(), + .layerLifecycleManager = mLayerLifecycleManager, + .forceUpdate = frontend::LayerSnapshotBuilder::ForceUpdateFlags::HIERARCHY, + .displays = mFrontEndDisplayInfos, + .displayChanges = true, + .globalShadowSettings = mDrawingState.globalShadowSettings, + .supportsBlur = mSupportsBlur, + .forceFullDamage = mForceFullDamage, + .excludeLayerIds = std::move(excludeLayerIds), + .supportedLayerGenericMetadata = + getHwComposer().getSupportedLayerGenericMetadata(), + .genericLayerMetadataKeyMap = getGenericLayerMetadataKeyMap()}; + mLayerSnapshotBuilder.update(args); + + auto getLayerSnapshotsFn = + getLayerSnapshotsForScreenshots(layerStack, uid, /*snapshotFilterFn=*/nullptr); + std::vector>> layers = getLayerSnapshotsFn(); + + args.excludeLayerIds.clear(); + mLayerSnapshotBuilder.update(args); + + return layers; + }; +} + std::function>>()> SurfaceFlinger::getLayerSnapshotsForScreenshots(uint32_t rootLayerId, uint32_t uid, std::unordered_set excludeLayerIds, diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 74d00dd60c..44847885ca 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -826,7 +826,9 @@ private: // If the uid provided is not UNSET_UID, the traverse will skip any layers that don't have a // matching ownerUid - void traverseLayersInLayerStack(ui::LayerStack, const int32_t uid, const LayerVector::Visitor&); + void traverseLayersInLayerStack(ui::LayerStack, const int32_t uid, + std::unordered_set excludeLayerIds, + const LayerVector::Visitor&); void readPersistentProperties(); @@ -1380,6 +1382,9 @@ private: std::optional layerStack, uint32_t uid, std::function snapshotFilterFn); + std::function>>()> getLayerSnapshotsForScreenshots( + std::optional layerStack, uint32_t uid, + std::unordered_set excludeLayerIds); std::function>>()> getLayerSnapshotsForScreenshots( uint32_t rootLayerId, uint32_t uid, std::unordered_set excludeLayerIds, bool childrenOnly, const std::optional& optionalParentCrop); diff --git a/services/surfaceflinger/tests/ScreenCapture_test.cpp b/services/surfaceflinger/tests/ScreenCapture_test.cpp index 976ee3519c..013694fd47 100644 --- a/services/surfaceflinger/tests/ScreenCapture_test.cpp +++ b/services/surfaceflinger/tests/ScreenCapture_test.cpp @@ -222,6 +222,14 @@ TEST_F(ScreenCaptureTest, CaptureLayerExclude) { mCapture->checkPixel(0, 0, 200, 200, 200); } +TEST_F(ScreenCaptureTest, CaptureLayerExcludeThroughDisplayArgs) { + mCaptureArgs.excludeHandles = {mFGSurfaceControl->getHandle()}; + ScreenCapture::captureDisplay(&mCapture, mCaptureArgs); + mCapture->expectBGColor(0, 0); + // Doesn't capture FG layer which is at 64, 64 + mCapture->expectBGColor(64, 64); +} + // Like the last test but verifies that children are also exclude. TEST_F(ScreenCaptureTest, CaptureLayerExcludeTree) { auto fgHandle = mFGSurfaceControl->getHandle(); diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index 19a93e1820..f5960614b0 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -204,7 +204,7 @@ void CompositionTest::captureScreenComposition() { auto traverseLayers = [this](const LayerVector::Visitor& visitor) { return mFlinger.traverseLayersInLayerStack(mDisplay->getLayerStack(), - CaptureArgs::UNSET_UID, visitor); + CaptureArgs::UNSET_UID, {}, visitor); }; auto getLayerSnapshots = RenderArea::fromTraverseLayersLambda(traverseLayers); diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index fc9e653ba4..89a190e9ea 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -446,8 +446,10 @@ public: } auto traverseLayersInLayerStack(ui::LayerStack layerStack, int32_t uid, + std::unordered_set excludeLayerIds, const LayerVector::Visitor& visitor) { - return mFlinger->SurfaceFlinger::traverseLayersInLayerStack(layerStack, uid, visitor); + return mFlinger->SurfaceFlinger::traverseLayersInLayerStack(layerStack, uid, + excludeLayerIds, visitor); } auto getDisplayNativePrimaries(const sp& displayToken, -- cgit v1.2.3-59-g8ed1b From 3e5965f3184a828a1b7ee2b5bd5d5c2177807a35 Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Fri, 7 Apr 2023 18:00:58 +0000 Subject: Support screenshots of HDR content Previously screenshots always rendered to either an SDR or a wide gamut colorspace. For screenshotting HDR content, this is only appropriate when the resulting screenshot (a) never leaves the device and (b) the relevant code has workarounds for the display to appropriately handle its luminance range. HDR screenshots will now have two paths: * A standard path for rendering to HLG. HLG was chosen because the OOTF shape is less hand-wavey than PQ's, does not require metadata, and bands less at 8-bits of color. * A special path for "display-native" screenshots. This is for use-cases like screen rotation where there are stricter color accuracy requirements for round-tripping. Skia already encodes the resulting screenshot by supplying an HLG CICP alongside a backwards-compatible transfer function, so it's only sufficient to change how SurfaceFlinger renders. Bug: 242324609 Bug: 276812775 Test: screencap binary Test: rotation animation Test: swiping in Recents Change-Id: Ic9edb92391d3beb38d076fba8f15e3fdcc2b8f50 --- libs/gui/LayerState.cpp | 4 +- libs/gui/aidl/android/gui/ISurfaceComposer.aidl | 4 + libs/gui/include/gui/DisplayCaptureArgs.h | 11 +- libs/renderengine/skia/SkiaRenderEngine.cpp | 6 +- libs/shaders/shaders.cpp | 58 ++++++---- services/surfaceflinger/DisplayRenderArea.cpp | 11 +- services/surfaceflinger/DisplayRenderArea.h | 4 +- services/surfaceflinger/LayerRenderArea.cpp | 5 +- services/surfaceflinger/LayerRenderArea.h | 3 +- services/surfaceflinger/RegionSamplingThread.cpp | 4 +- services/surfaceflinger/RenderArea.h | 12 ++- services/surfaceflinger/ScreenCaptureOutput.cpp | 2 +- services/surfaceflinger/ScreenCaptureOutput.h | 2 + services/surfaceflinger/SurfaceFlinger.cpp | 118 ++++++++++++++------- .../fuzzer/surfaceflinger_layer_fuzzer.cpp | 3 +- .../tests/unittests/CompositionTest.cpp | 2 +- 16 files changed, 173 insertions(+), 76 deletions(-) (limited to 'libs/gui/LayerState.cpp') diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index fee91a40c2..2322b70d1c 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -897,11 +897,11 @@ status_t CaptureArgs::writeToParcel(Parcel* output) const { SAFE_PARCEL(output->writeInt32, static_cast(dataspace)); SAFE_PARCEL(output->writeBool, allowProtected); SAFE_PARCEL(output->writeBool, grayscale); - SAFE_PARCEL(output->writeInt32, excludeHandles.size()); for (auto& excludeHandle : excludeHandles) { SAFE_PARCEL(output->writeStrongBinder, excludeHandle); } + SAFE_PARCEL(output->writeBool, hintForSeamlessTransition); return NO_ERROR; } @@ -918,7 +918,6 @@ status_t CaptureArgs::readFromParcel(const Parcel* input) { dataspace = static_cast(value); SAFE_PARCEL(input->readBool, &allowProtected); SAFE_PARCEL(input->readBool, &grayscale); - int32_t numExcludeHandles = 0; SAFE_PARCEL_READ_SIZE(input->readInt32, &numExcludeHandles, input->dataSize()); excludeHandles.reserve(numExcludeHandles); @@ -927,6 +926,7 @@ status_t CaptureArgs::readFromParcel(const Parcel* input) { SAFE_PARCEL(input->readStrongBinder, &binder); excludeHandles.emplace(binder); } + SAFE_PARCEL(input->readBool, &hintForSeamlessTransition); return NO_ERROR; } diff --git a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl index aa58e2e580..ec3266ca83 100644 --- a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl +++ b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl @@ -230,6 +230,10 @@ interface ISurfaceComposer { */ void captureDisplay(in DisplayCaptureArgs args, IScreenCaptureListener listener); + /** + * Capture the specified screen. This requires the READ_FRAME_BUFFER + * permission. + */ void captureDisplayById(long displayId, IScreenCaptureListener listener); /** diff --git a/libs/gui/include/gui/DisplayCaptureArgs.h b/libs/gui/include/gui/DisplayCaptureArgs.h index 5c794aea37..2676e0a338 100644 --- a/libs/gui/include/gui/DisplayCaptureArgs.h +++ b/libs/gui/include/gui/DisplayCaptureArgs.h @@ -41,7 +41,7 @@ struct CaptureArgs : public Parcelable { bool captureSecureLayers{false}; int32_t uid{UNSET_UID}; // Force capture to be in a color space. If the value is ui::Dataspace::UNKNOWN, the captured - // result will be in the display's colorspace. + // result will be in a colorspace appropriate for capturing the display contents // The display may use non-RGB dataspace (ex. displayP3) that could cause pixel data could be // different from SRGB (byte per color), and failed when checking colors in tests. // NOTE: In normal cases, we want the screen to be captured in display's colorspace. @@ -59,6 +59,15 @@ struct CaptureArgs : public Parcelable { std::unordered_set, SpHash> excludeHandles; + // Hint that the caller will use the screenshot animation as part of a transition animation. + // The canonical example would be screen rotation - in such a case any color shift in the + // screenshot is a detractor so composition in the display's colorspace is required. + // Otherwise, the system may choose a colorspace that is more appropriate for use-cases + // such as file encoding or for blending HDR content into an ap's UI, where the display's + // exact colorspace is not an appropriate intermediate result. + // Note that if the caller is requesting a specific dataspace, this hint does nothing. + bool hintForSeamlessTransition = false; + virtual status_t writeToParcel(Parcel* output) const; virtual status_t readFromParcel(const Parcel* input); }; diff --git a/libs/renderengine/skia/SkiaRenderEngine.cpp b/libs/renderengine/skia/SkiaRenderEngine.cpp index 8256dd8e69..2a51493cea 100644 --- a/libs/renderengine/skia/SkiaRenderEngine.cpp +++ b/libs/renderengine/skia/SkiaRenderEngine.cpp @@ -517,16 +517,18 @@ sk_sp SkiaRenderEngine::createRuntimeEffectShader( } else { runtimeEffect = effectIter->second; } + mat4 colorTransform = parameters.layer.colorTransform; colorTransform *= mat4::scale(vec4(parameters.layerDimmingRatio, parameters.layerDimmingRatio, parameters.layerDimmingRatio, 1.f)); + const auto targetBuffer = parameters.layer.source.buffer.buffer; const auto graphicBuffer = targetBuffer ? targetBuffer->getBuffer() : nullptr; const auto hardwareBuffer = graphicBuffer ? graphicBuffer->toAHardwareBuffer() : nullptr; - return createLinearEffectShader(parameters.shader, effect, runtimeEffect, colorTransform, - parameters.display.maxLuminance, + return createLinearEffectShader(parameters.shader, effect, runtimeEffect, + std::move(colorTransform), parameters.display.maxLuminance, parameters.display.currentLuminanceNits, parameters.layer.source.buffer.maxLuminanceNits, hardwareBuffer, parameters.display.renderIntent); diff --git a/libs/shaders/shaders.cpp b/libs/shaders/shaders.cpp index a3c403e551..19518eaecc 100644 --- a/libs/shaders/shaders.cpp +++ b/libs/shaders/shaders.cpp @@ -191,31 +191,35 @@ void generateLuminanceScalesForOOTF(ui::Dataspace inputDataspace, ui::Dataspace )"); break; default: + // Input is SDR so map to its white point luminance switch (outputDataspace & HAL_DATASPACE_TRANSFER_MASK) { - case HAL_DATASPACE_TRANSFER_ST2084: + // Max HLG output is nominally 1000 nits, but BT. 2100-2 allows + // for gamma correcting the HLG OOTF for displays with a different + // dynamic range. Scale to 1000 nits to apply an inverse OOTF against + // a reference display correctly. + // TODO: Use knowledge of the dimming ratio here to prevent + // unintended gamma shaft. case HAL_DATASPACE_TRANSFER_HLG: - // SDR -> HDR tonemap shader.append(R"( float3 ScaleLuminance(float3 xyz) { - return xyz * in_libtonemap_inputMaxLuminance; + return xyz * 1000.0; } )"); break; default: - // Input and output are both SDR, so no tone-mapping is expected so - // no-op the luminance normalization. shader.append(R"( - float3 ScaleLuminance(float3 xyz) { - return xyz * in_libtonemap_displayMaxLuminance; - } - )"); + float3 ScaleLuminance(float3 xyz) { + return xyz * in_libtonemap_displayMaxLuminance; + } + )"); break; } } } // Normalizes from absolute light back to relative light (maps from [0, maxNits] back to [0, 1]) -static void generateLuminanceNormalizationForOOTF(ui::Dataspace outputDataspace, +static void generateLuminanceNormalizationForOOTF(ui::Dataspace inputDataspace, + ui::Dataspace outputDataspace, std::string& shader) { switch (outputDataspace & HAL_DATASPACE_TRANSFER_MASK) { case HAL_DATASPACE_TRANSFER_ST2084: @@ -226,11 +230,28 @@ static void generateLuminanceNormalizationForOOTF(ui::Dataspace outputDataspace, )"); break; case HAL_DATASPACE_TRANSFER_HLG: - shader.append(R"( - float3 NormalizeLuminance(float3 xyz) { - return xyz / 1000.0; - } - )"); + switch (inputDataspace & HAL_DATASPACE_TRANSFER_MASK) { + case HAL_DATASPACE_TRANSFER_HLG: + shader.append(R"( + float3 NormalizeLuminance(float3 xyz) { + return xyz / 1000.0; + } + )"); + break; + default: + // Transcoding to HLG requires applying the inverse OOTF + // with the expectation that the OOTF is then applied during + // tonemapping downstream. + shader.append(R"( + float3 NormalizeLuminance(float3 xyz) { + // BT. 2100-2 operates on normalized luminances, + // so renormalize to the input + float ootfGain = pow(xyz.y / 1000.0, -0.2 / 1.2) / 1000.0; + return xyz * ootfGain; + } + )"); + break; + } break; default: shader.append(R"( @@ -250,7 +271,7 @@ void generateOOTF(ui::Dataspace inputDataspace, ui::Dataspace outputDataspace, .c_str()); generateLuminanceScalesForOOTF(inputDataspace, outputDataspace, shader); - generateLuminanceNormalizationForOOTF(outputDataspace, shader); + generateLuminanceNormalizationForOOTF(inputDataspace, outputDataspace, shader); shader.append(R"( float3 OOTF(float3 linearRGB, float3 xyz) { @@ -501,9 +522,8 @@ std::vector buildLinearEffectUniforms( tonemap::Metadata metadata{.displayMaxLuminance = maxDisplayLuminance, // If the input luminance is unknown, use display luminance (aka, - // no-op any luminance changes) - // This will be the case for eg screenshots in addition to - // uncalibrated displays + // no-op any luminance changes). + // This is expected to only be meaningful for PQ content .contentMaxLuminance = maxLuminance > 0 ? maxLuminance : maxDisplayLuminance, .currentDisplayLuminance = currentDisplayLuminanceNits > 0 diff --git a/services/surfaceflinger/DisplayRenderArea.cpp b/services/surfaceflinger/DisplayRenderArea.cpp index 8f39e26e0f..e55cd3ea42 100644 --- a/services/surfaceflinger/DisplayRenderArea.cpp +++ b/services/surfaceflinger/DisplayRenderArea.cpp @@ -35,21 +35,24 @@ std::unique_ptr DisplayRenderArea::create(wp di const Rect& sourceCrop, ui::Size reqSize, ui::Dataspace reqDataSpace, bool useIdentityTransform, + bool hintForSeamlessTransition, bool allowSecureLayers) { if (auto display = displayWeak.promote()) { // Using new to access a private constructor. return std::unique_ptr( new DisplayRenderArea(std::move(display), sourceCrop, reqSize, reqDataSpace, - useIdentityTransform, allowSecureLayers)); + useIdentityTransform, hintForSeamlessTransition, + allowSecureLayers)); } return nullptr; } DisplayRenderArea::DisplayRenderArea(sp display, const Rect& sourceCrop, ui::Size reqSize, ui::Dataspace reqDataSpace, - bool useIdentityTransform, bool allowSecureLayers) - : RenderArea(reqSize, CaptureFill::OPAQUE, reqDataSpace, allowSecureLayers, - applyDeviceOrientation(useIdentityTransform, *display)), + bool useIdentityTransform, bool hintForSeamlessTransition, + bool allowSecureLayers) + : RenderArea(reqSize, CaptureFill::OPAQUE, reqDataSpace, hintForSeamlessTransition, + allowSecureLayers, applyDeviceOrientation(useIdentityTransform, *display)), mDisplay(std::move(display)), mSourceCrop(sourceCrop) {} diff --git a/services/surfaceflinger/DisplayRenderArea.h b/services/surfaceflinger/DisplayRenderArea.h index ce5410a90d..9a4981c881 100644 --- a/services/surfaceflinger/DisplayRenderArea.h +++ b/services/surfaceflinger/DisplayRenderArea.h @@ -30,6 +30,7 @@ public: static std::unique_ptr create(wp, const Rect& sourceCrop, ui::Size reqSize, ui::Dataspace, bool useIdentityTransform, + bool hintForSeamlessTransition, bool allowSecureLayers = true); const ui::Transform& getTransform() const override; @@ -39,7 +40,8 @@ public: private: DisplayRenderArea(sp, const Rect& sourceCrop, ui::Size reqSize, - ui::Dataspace, bool useIdentityTransform, bool allowSecureLayers = true); + ui::Dataspace, bool useIdentityTransform, bool hintForSeamlessTransition, + bool allowSecureLayers = true); const sp mDisplay; const Rect mSourceCrop; diff --git a/services/surfaceflinger/LayerRenderArea.cpp b/services/surfaceflinger/LayerRenderArea.cpp index 1b8ff28a76..f6b5afc6a8 100644 --- a/services/surfaceflinger/LayerRenderArea.cpp +++ b/services/surfaceflinger/LayerRenderArea.cpp @@ -40,8 +40,9 @@ void reparentForDrawing(const sp& oldParent, const sp& newParent, LayerRenderArea::LayerRenderArea(SurfaceFlinger& flinger, sp layer, const Rect& crop, ui::Size reqSize, ui::Dataspace reqDataSpace, bool childrenOnly, bool allowSecureLayers, const ui::Transform& layerTransform, - const Rect& layerBufferSize) - : RenderArea(reqSize, CaptureFill::CLEAR, reqDataSpace, allowSecureLayers), + const Rect& layerBufferSize, bool hintForSeamlessTransition) + : RenderArea(reqSize, CaptureFill::CLEAR, reqDataSpace, hintForSeamlessTransition, + allowSecureLayers), mLayer(std::move(layer)), mLayerTransform(layerTransform), mLayerBufferSize(layerBufferSize), diff --git a/services/surfaceflinger/LayerRenderArea.h b/services/surfaceflinger/LayerRenderArea.h index 9bb13b3d6a..aa609eea38 100644 --- a/services/surfaceflinger/LayerRenderArea.h +++ b/services/surfaceflinger/LayerRenderArea.h @@ -34,7 +34,8 @@ class LayerRenderArea : public RenderArea { public: LayerRenderArea(SurfaceFlinger& flinger, sp layer, const Rect& crop, ui::Size reqSize, ui::Dataspace reqDataSpace, bool childrenOnly, bool allowSecureLayers, - const ui::Transform& layerTransform, const Rect& layerBufferSize); + const ui::Transform& layerTransform, const Rect& layerBufferSize, + bool hintForSeamlessTransition); const ui::Transform& getTransform() const override; bool isSecure() const override; diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp index 531d277ffc..8f658d5a09 100644 --- a/services/surfaceflinger/RegionSamplingThread.cpp +++ b/services/surfaceflinger/RegionSamplingThread.cpp @@ -277,10 +277,12 @@ void RegionSamplingThread::captureSample() { const Rect sampledBounds = sampleRegion.bounds(); constexpr bool kUseIdentityTransform = false; + constexpr bool kHintForSeamlessTransition = false; SurfaceFlinger::RenderAreaFuture renderAreaFuture = ftl::defer([=] { return DisplayRenderArea::create(displayWeak, sampledBounds, sampledBounds.getSize(), - ui::Dataspace::V0_SRGB, kUseIdentityTransform); + ui::Dataspace::V0_SRGB, kUseIdentityTransform, + kHintForSeamlessTransition); }); std::unordered_set, SpHash> listeners; diff --git a/services/surfaceflinger/RenderArea.h b/services/surfaceflinger/RenderArea.h index 910fce043c..71b85bd3b2 100644 --- a/services/surfaceflinger/RenderArea.h +++ b/services/surfaceflinger/RenderArea.h @@ -25,12 +25,14 @@ public: static float getCaptureFillValue(CaptureFill captureFill); RenderArea(ui::Size reqSize, CaptureFill captureFill, ui::Dataspace reqDataSpace, - bool allowSecureLayers = false, RotationFlags rotation = ui::Transform::ROT_0) + bool hintForSeamlessTransition, bool allowSecureLayers = false, + RotationFlags rotation = ui::Transform::ROT_0) : mAllowSecureLayers(allowSecureLayers), mReqSize(reqSize), mReqDataSpace(reqDataSpace), mCaptureFill(captureFill), - mRotationFlags(rotation) {} + mRotationFlags(rotation), + mHintForSeamlessTransition(hintForSeamlessTransition) {} static std::function>>()> fromTraverseLayersLambda( std::function traverseLayers) { @@ -90,6 +92,10 @@ public: // capture operation. virtual sp getParentLayer() const { return nullptr; } + // Returns whether the render result may be used for system animations that + // must preserve the exact colors of the display. + bool getHintForSeamlessTransition() const { return mHintForSeamlessTransition; } + protected: const bool mAllowSecureLayers; @@ -98,7 +104,7 @@ private: const ui::Dataspace mReqDataSpace; const CaptureFill mCaptureFill; const RotationFlags mRotationFlags; - const Rect mLayerStackSpaceRect; + const bool mHintForSeamlessTransition; }; } // namespace android diff --git a/services/surfaceflinger/ScreenCaptureOutput.cpp b/services/surfaceflinger/ScreenCaptureOutput.cpp index a1d5cd7379..b70b53d05a 100644 --- a/services/surfaceflinger/ScreenCaptureOutput.cpp +++ b/services/surfaceflinger/ScreenCaptureOutput.cpp @@ -36,6 +36,7 @@ std::shared_ptr createScreenCaptureOutput(ScreenCaptureOutp output->setLayerFilter({args.layerStack}); output->setRenderSurface(std::make_unique(std::move(args.buffer))); output->setDisplayBrightness(args.sdrWhitePointNits, args.displayBrightnessNits); + output->editState().clientTargetBrightness = args.targetBrightness; output->setDisplayColorProfile(std::make_unique( compositionengine::DisplayColorProfileCreationArgsBuilder() @@ -75,7 +76,6 @@ renderengine::DisplaySettings ScreenCaptureOutput::generateClientCompositionDisp auto clientCompositionDisplay = compositionengine::impl::Output::generateClientCompositionDisplaySettings(); clientCompositionDisplay.clip = mRenderArea.getSourceCrop(); - clientCompositionDisplay.targetLuminanceNits = -1; return clientCompositionDisplay; } diff --git a/services/surfaceflinger/ScreenCaptureOutput.h b/services/surfaceflinger/ScreenCaptureOutput.h index 4e5a0ccfd2..3c307b0733 100644 --- a/services/surfaceflinger/ScreenCaptureOutput.h +++ b/services/surfaceflinger/ScreenCaptureOutput.h @@ -33,6 +33,8 @@ struct ScreenCaptureOutputArgs { std::shared_ptr buffer; float sdrWhitePointNits; float displayBrightnessNits; + // Counterintuitively, when targetBrightness > 1.0 then dim the scene. + float targetBrightness; bool regionSampling; }; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index c88bff5ed8..d406afff1f 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -6915,6 +6915,32 @@ status_t SurfaceFlinger::setSchedAttr(bool enabled) { return NO_ERROR; } +namespace { + +ui::Dataspace pickBestDataspace(ui::Dataspace requestedDataspace, const DisplayDevice* display, + bool capturingHdrLayers, bool hintForSeamlessTransition) { + if (requestedDataspace != ui::Dataspace::UNKNOWN || display == nullptr) { + return requestedDataspace; + } + + const auto& state = display->getCompositionDisplay()->getState(); + + const auto dataspaceForColorMode = ui::pickDataspaceFor(state.colorMode); + + if (capturingHdrLayers && !hintForSeamlessTransition) { + // For now since we only support 8-bit screenshots, just use HLG and + // assume that 1.0 >= display max luminance. This isn't quite as future + // proof as PQ is, but is good enough. + // Consider using PQ once we support 16-bit screenshots and we're able + // to consistently supply metadata to image encoders. + return ui::Dataspace::BT2020_HLG; + } + + return dataspaceForColorMode; +} + +} // namespace + status_t SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args, const sp& captureListener) { ATRACE_CALL(); @@ -6930,7 +6956,6 @@ status_t SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args, ui::LayerStack layerStack; ui::Size reqSize(args.width, args.height); std::unordered_set excludeLayerIds; - ui::Dataspace dataspace; { Mutex::Autolock lock(mStateLock); sp display = getDisplayDeviceLocked(args.displayToken); @@ -6952,17 +6977,12 @@ status_t SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args, return NAME_NOT_FOUND; } } - - // Allow the caller to specify a dataspace regardless of the display's color mode, e.g. if - // it wants sRGB regardless of the display's wide color mode. - dataspace = args.dataspace == ui::Dataspace::UNKNOWN - ? ui::pickDataspaceFor(display->getCompositionDisplay()->getState().colorMode) - : args.dataspace; } RenderAreaFuture renderAreaFuture = ftl::defer([=] { - return DisplayRenderArea::create(displayWeak, args.sourceCrop, reqSize, dataspace, - args.useIdentityTransform, args.captureSecureLayers); + return DisplayRenderArea::create(displayWeak, args.sourceCrop, reqSize, + ui::Dataspace::UNKNOWN, args.useIdentityTransform, + args.hintForSeamlessTransition, args.captureSecureLayers); }); GetLayerSnapshotsFunction getLayerSnapshots; @@ -6988,7 +7008,6 @@ status_t SurfaceFlinger::captureDisplay(DisplayId displayId, ui::LayerStack layerStack; wp displayWeak; ui::Size size; - ui::Dataspace dataspace; { Mutex::Autolock lock(mStateLock); @@ -7000,12 +7019,12 @@ status_t SurfaceFlinger::captureDisplay(DisplayId displayId, displayWeak = display; layerStack = display->getLayerStack(); size = display->getLayerStackSpaceRect().getSize(); - dataspace = ui::pickDataspaceFor(display->getCompositionDisplay()->getState().colorMode); } RenderAreaFuture renderAreaFuture = ftl::defer([=] { - return DisplayRenderArea::create(displayWeak, Rect(), size, dataspace, + return DisplayRenderArea::create(displayWeak, Rect(), size, ui::Dataspace::UNKNOWN, false /* useIdentityTransform */, + false /* hintForSeamlessTransition */, false /* captureSecureLayers */); }); @@ -7047,7 +7066,7 @@ status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, sp parent; Rect crop(args.sourceCrop); std::unordered_set excludeLayerIds; - ui::Dataspace dataspace; + ui::Dataspace dataspace = args.dataspace; // Call this before holding mStateLock to avoid any deadlocking. bool canCaptureBlackoutContent = hasCaptureBlackoutContentPermission(); @@ -7094,12 +7113,6 @@ status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, return NAME_NOT_FOUND; } } - - // The dataspace is depended on the color mode of display, that could use non-native mode - // (ex. displayP3) to enhance the content, but some cases are checking native RGB in bytes, - // and failed if display is not in native mode. This provide a way to force using native - // colors when capture. - dataspace = args.dataspace; } // mStateLock // really small crop or frameScale @@ -7128,7 +7141,8 @@ status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, return std::make_unique(*this, parent, crop, reqSize, dataspace, childrenOnly, args.captureSecureLayers, - layerTransform, layerBufferSize); + layerTransform, layerBufferSize, + args.hintForSeamlessTransition); }); GetLayerSnapshotsFunction getLayerSnapshots; if (mLayerLifecycleManagerEnabled) { @@ -7314,29 +7328,48 @@ ftl::SharedFuture SurfaceFlinger::renderScreenImpl( return ftl::yield(base::unexpected(PERMISSION_DENIED)).share(); } - captureResults.buffer = buffer->getBuffer(); - auto dataspace = renderArea->getReqDataSpace(); + auto capturedBuffer = buffer; + + auto requestedDataspace = renderArea->getReqDataSpace(); auto parent = renderArea->getParentLayer(); auto renderIntent = RenderIntent::TONE_MAP_COLORIMETRIC; auto sdrWhitePointNits = DisplayDevice::sDefaultMaxLumiance; auto displayBrightnessNits = DisplayDevice::sDefaultMaxLumiance; - if (dataspace == ui::Dataspace::UNKNOWN && parent) { + captureResults.capturedDataspace = requestedDataspace; + + { Mutex::Autolock lock(mStateLock); - auto display = findDisplay([layerStack = parent->getLayerStack()](const auto& display) { - return display.getLayerStack() == layerStack; - }); - if (!display) { - // If the layer is not on a display, use the dataspace for the default display. - display = getDefaultDisplayDeviceLocked(); + const DisplayDevice* display = nullptr; + if (parent) { + display = findDisplay([layerStack = parent->getLayerStack()](const auto& display) { + return display.getLayerStack() == layerStack; + }).get(); + } + + if (display == nullptr) { + display = renderArea->getDisplayDevice().get(); + } + + if (display == nullptr) { + display = getDefaultDisplayDeviceLocked().get(); } - dataspace = ui::pickDataspaceFor(display->getCompositionDisplay()->getState().colorMode); - renderIntent = display->getCompositionDisplay()->getState().renderIntent; - sdrWhitePointNits = display->getCompositionDisplay()->getState().sdrWhitePointNits; - displayBrightnessNits = display->getCompositionDisplay()->getState().displayBrightnessNits; + if (display != nullptr) { + const auto& state = display->getCompositionDisplay()->getState(); + captureResults.capturedDataspace = + pickBestDataspace(requestedDataspace, display, captureResults.capturedHdrLayers, + renderArea->getHintForSeamlessTransition()); + sdrWhitePointNits = state.sdrWhitePointNits; + displayBrightnessNits = state.displayBrightnessNits; + + if (requestedDataspace == ui::Dataspace::UNKNOWN) { + renderIntent = state.renderIntent; + } + } } - captureResults.capturedDataspace = dataspace; + + captureResults.buffer = capturedBuffer->getBuffer(); ui::LayerStack layerStack{ui::DEFAULT_LAYER_STACK}; if (!layers.empty()) { @@ -7353,9 +7386,9 @@ ftl::SharedFuture SurfaceFlinger::renderScreenImpl( return layerFEs; }; - auto present = [this, buffer = std::move(buffer), dataspace, sdrWhitePointNits, - displayBrightnessNits, grayscale, layerFEs = copyLayerFEs(), layerStack, - regionSampling, renderArea = std::move(renderArea), + auto present = [this, buffer = capturedBuffer, dataspace = captureResults.capturedDataspace, + sdrWhitePointNits, displayBrightnessNits, grayscale, layerFEs = copyLayerFEs(), + layerStack, regionSampling, renderArea = std::move(renderArea), renderIntent]() -> FenceResult { std::unique_ptr compositionEngine = mFactory.createCompositionEngine(); @@ -7364,6 +7397,16 @@ ftl::SharedFuture SurfaceFlinger::renderScreenImpl( compositionengine::Output::ColorProfile colorProfile{.dataspace = dataspace, .renderIntent = renderIntent}; + float targetBrightness = 1.0f; + if (dataspace == ui::Dataspace::BT2020_HLG) { + const float maxBrightnessNits = displayBrightnessNits / sdrWhitePointNits * 203; + // With a low dimming ratio, don't fit the entire curve. Otherwise mixed content + // will appear way too bright. + if (maxBrightnessNits < 1000.f) { + targetBrightness = 1000.f / maxBrightnessNits; + } + } + std::shared_ptr output = createScreenCaptureOutput( ScreenCaptureOutputArgs{.compositionEngine = *compositionEngine, .colorProfile = colorProfile, @@ -7372,6 +7415,7 @@ ftl::SharedFuture SurfaceFlinger::renderScreenImpl( .buffer = std::move(buffer), .sdrWhitePointNits = sdrWhitePointNits, .displayBrightnessNits = displayBrightnessNits, + .targetBrightness = targetBrightness, .regionSampling = regionSampling}); const float colorSaturation = grayscale ? 0 : 1; diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp index c3dcb85686..921cae4e41 100644 --- a/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp +++ b/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp @@ -177,7 +177,8 @@ void LayerFuzzer::invokeBufferStateLayer() { {mFdp.ConsumeIntegral(), mFdp.ConsumeIntegral()} /*reqSize*/, mFdp.PickValueInArray(kDataspaces), mFdp.ConsumeBool(), - mFdp.ConsumeBool(), getFuzzedTransform(), getFuzzedRect()); + mFdp.ConsumeBool(), getFuzzedTransform(), getFuzzedRect(), + mFdp.ConsumeBool()); layerArea.render([]() {} /*drawLayers*/); if (!ownsHandle) { diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index 156007b862..6ca21bd458 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -200,7 +200,7 @@ void CompositionTest::captureScreenComposition() { constexpr bool regionSampling = false; auto renderArea = DisplayRenderArea::create(mDisplay, sourceCrop, sourceCrop.getSize(), - ui::Dataspace::V0_SRGB, ui::Transform::ROT_0); + ui::Dataspace::V0_SRGB, true, true); auto traverseLayers = [this](const LayerVector::Visitor& visitor) { return mFlinger.traverseLayersInLayerStack(mDisplay->getLayerStack(), -- cgit v1.2.3-59-g8ed1b