summaryrefslogtreecommitdiff
path: root/services/surfaceflinger/CompositionEngine/src/planner
diff options
context:
space:
mode:
Diffstat (limited to 'services/surfaceflinger/CompositionEngine/src/planner')
-rw-r--r--services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp417
-rw-r--r--services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp545
-rw-r--r--services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp184
-rw-r--r--services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp336
-rw-r--r--services/surfaceflinger/CompositionEngine/src/planner/Predictor.cpp481
-rw-r--r--services/surfaceflinger/CompositionEngine/src/planner/TexturePool.cpp84
6 files changed, 0 insertions, 2047 deletions
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
deleted file mode 100644
index c1cd5ab5fd..0000000000
--- a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
+++ /dev/null
@@ -1,417 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#undef LOG_TAG
-#define LOG_TAG "Planner"
-// #define LOG_NDEBUG 0
-#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-
-#include <android-base/properties.h>
-#include <compositionengine/impl/OutputCompositionState.h>
-#include <compositionengine/impl/planner/CachedSet.h>
-#include <math/HashCombine.h>
-#include <renderengine/DisplaySettings.h>
-#include <renderengine/RenderEngine.h>
-#include <utils/Trace.h>
-
-#include <utils/Trace.h>
-
-namespace android::compositionengine::impl::planner {
-
-const bool CachedSet::sDebugHighlighLayers =
- base::GetBoolProperty(std::string("debug.sf.layer_caching_highlight"), false);
-
-std::string durationString(std::chrono::milliseconds duration) {
- using namespace std::chrono_literals;
-
- std::string result;
-
- if (duration >= 1h) {
- const auto hours = std::chrono::duration_cast<std::chrono::hours>(duration);
- base::StringAppendF(&result, "%d hr ", static_cast<int>(hours.count()));
- duration -= hours;
- }
- if (duration >= 1min) {
- const auto minutes = std::chrono::duration_cast<std::chrono::minutes>(duration);
- base::StringAppendF(&result, "%d min ", static_cast<int>(minutes.count()));
- duration -= minutes;
- }
- base::StringAppendF(&result, "%.3f sec ", duration.count() / 1000.0f);
-
- return result;
-}
-
-CachedSet::Layer::Layer(const LayerState* state, std::chrono::steady_clock::time_point lastUpdate)
- : mState(state), mHash(state->getHash()), mLastUpdate(lastUpdate) {}
-
-CachedSet::CachedSet(const LayerState* layer, std::chrono::steady_clock::time_point lastUpdate)
- : mFingerprint(layer->getHash()), mLastUpdate(lastUpdate) {
- addLayer(layer, lastUpdate);
-}
-
-CachedSet::CachedSet(Layer layer)
- : mFingerprint(layer.getHash()),
- mLastUpdate(layer.getLastUpdate()),
- mBounds(layer.getDisplayFrame()),
- mVisibleRegion(layer.getVisibleRegion()) {
- mLayers.emplace_back(std::move(layer));
-}
-
-void CachedSet::addLayer(const LayerState* layer,
- std::chrono::steady_clock::time_point lastUpdate) {
- mLayers.emplace_back(layer, lastUpdate);
-
- Region boundingRegion;
- boundingRegion.orSelf(mBounds);
- boundingRegion.orSelf(layer->getDisplayFrame());
- mBounds = boundingRegion.getBounds();
- mVisibleRegion.orSelf(layer->getVisibleRegion());
-}
-
-NonBufferHash CachedSet::getNonBufferHash() const {
- if (mLayers.size() == 1) {
- return mFingerprint;
- }
-
- // TODO(b/182614524): We sometimes match this with LayerState hashes. Determine if that is
- // necessary (and therefore we need to match implementations).
- size_t hash = 0;
- android::hashCombineSingle(hash, mBounds);
- android::hashCombineSingle(hash, mOutputDataspace);
- android::hashCombineSingle(hash, mOrientation);
- return hash;
-}
-
-size_t CachedSet::getComponentDisplayCost() const {
- size_t displayCost = 0;
-
- for (const Layer& layer : mLayers) {
- displayCost += static_cast<size_t>(layer.getDisplayFrame().width() *
- layer.getDisplayFrame().height());
- }
-
- return displayCost;
-}
-
-size_t CachedSet::getCreationCost() const {
- if (mLayers.size() == 1) {
- return 0;
- }
-
- // Reads
- size_t creationCost = getComponentDisplayCost();
-
- // Write - assumes that the output buffer only gets written once per pixel
- creationCost += static_cast<size_t>(mBounds.width() * mBounds.height());
-
- return creationCost;
-}
-
-size_t CachedSet::getDisplayCost() const {
- return static_cast<size_t>(mBounds.width() * mBounds.height());
-}
-
-bool CachedSet::hasBufferUpdate() const {
- for (const Layer& layer : mLayers) {
- if (layer.getFramesSinceBufferUpdate() == 0) {
- return true;
- }
- }
- return false;
-}
-
-bool CachedSet::hasReadyBuffer() const {
- return mTexture && mDrawFence->getStatus() == Fence::Status::Signaled;
-}
-
-std::vector<CachedSet> CachedSet::decompose() const {
- std::vector<CachedSet> layers;
-
- std::transform(mLayers.begin(), mLayers.end(), std::back_inserter(layers),
- [](Layer layer) { return CachedSet(std::move(layer)); });
-
- return layers;
-}
-
-void CachedSet::updateAge(std::chrono::steady_clock::time_point now) {
- LOG_ALWAYS_FATAL_IF(mLayers.size() > 1, "[%s] This should only be called on single-layer sets",
- __func__);
-
- if (mLayers[0].getFramesSinceBufferUpdate() == 0) {
- mLastUpdate = now;
- mAge = 0;
- }
-}
-
-void CachedSet::render(renderengine::RenderEngine& renderEngine, TexturePool& texturePool,
- const OutputCompositionState& outputState) {
- ATRACE_CALL();
- const Rect& viewport = outputState.layerStackSpace.content;
- const ui::Dataspace& outputDataspace = outputState.dataspace;
- const ui::Transform::RotationFlags orientation =
- ui::Transform::toRotationFlags(outputState.framebufferSpace.orientation);
-
- renderengine::DisplaySettings displaySettings{
- .physicalDisplay = outputState.framebufferSpace.content,
- .clip = viewport,
- .outputDataspace = outputDataspace,
- .orientation = orientation,
- };
-
- Region clearRegion = Region::INVALID_REGION;
- LayerFE::ClientCompositionTargetSettings targetSettings{
- .clip = Region(viewport),
- .needsFiltering = false,
- .isSecure = outputState.isSecure,
- .supportsProtectedContent = false,
- .clearRegion = clearRegion,
- .viewport = viewport,
- .dataspace = outputDataspace,
- .realContentIsVisible = true,
- .clearContent = false,
- .blurSetting = LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled,
- };
-
- std::vector<renderengine::LayerSettings> layerSettings;
- renderengine::LayerSettings highlight;
- for (const auto& layer : mLayers) {
- const auto clientCompositionList =
- layer.getState()->getOutputLayer()->getLayerFE().prepareClientCompositionList(
- targetSettings);
- layerSettings.insert(layerSettings.end(), clientCompositionList.cbegin(),
- clientCompositionList.cend());
- }
-
- std::vector<const renderengine::LayerSettings*> layerSettingsPointers;
- std::transform(layerSettings.cbegin(), layerSettings.cend(),
- std::back_inserter(layerSettingsPointers),
- [](const renderengine::LayerSettings& settings) { return &settings; });
-
- renderengine::LayerSettings blurLayerSettings;
- if (mBlurLayer) {
- auto blurSettings = targetSettings;
- blurSettings.blurSetting =
- LayerFE::ClientCompositionTargetSettings::BlurSetting::BackgroundBlurOnly;
- auto clientCompositionList =
- mBlurLayer->getOutputLayer()->getLayerFE().prepareClientCompositionList(
- blurSettings);
- blurLayerSettings = clientCompositionList.back();
- // This mimics Layer::prepareClearClientComposition
- blurLayerSettings.skipContentDraw = true;
- blurLayerSettings.name = std::string("blur layer");
- // Clear out the shadow settings
- blurLayerSettings.shadow = {};
- layerSettingsPointers.push_back(&blurLayerSettings);
- }
-
- renderengine::LayerSettings holePunchSettings;
- renderengine::LayerSettings holePunchBackgroundSettings;
- if (mHolePunchLayer) {
- auto clientCompositionList =
- mHolePunchLayer->getOutputLayer()->getLayerFE().prepareClientCompositionList(
- targetSettings);
- // Assume that the final layer contains the buffer that we want to
- // replace with a hole punch.
- holePunchSettings = clientCompositionList.back();
- // This mimics Layer::prepareClearClientComposition
- holePunchSettings.source.buffer.buffer = nullptr;
- holePunchSettings.source.solidColor = half3(0.0f, 0.0f, 0.0f);
- holePunchSettings.disableBlending = true;
- holePunchSettings.alpha = 0.0f;
- holePunchSettings.name = std::string("hole punch layer");
- layerSettingsPointers.push_back(&holePunchSettings);
-
- // Add a solid background as the first layer in case there is no opaque
- // buffer behind the punch hole
- holePunchBackgroundSettings.alpha = 1.0f;
- holePunchBackgroundSettings.name = std::string("holePunchBackground");
- holePunchBackgroundSettings.geometry.boundaries = holePunchSettings.geometry.boundaries;
- holePunchBackgroundSettings.geometry.positionTransform =
- holePunchSettings.geometry.positionTransform;
- layerSettingsPointers.insert(layerSettingsPointers.begin(), &holePunchBackgroundSettings);
- }
-
- if (sDebugHighlighLayers) {
- highlight = {
- .geometry =
- renderengine::Geometry{
- .boundaries = FloatRect(0.0f, 0.0f,
- static_cast<float>(mBounds.getWidth()),
- static_cast<float>(mBounds.getHeight())),
- },
- .source =
- renderengine::PixelSource{
- .solidColor = half3(0.25f, 0.0f, 0.5f),
- },
- .alpha = half(0.05f),
- };
-
- layerSettingsPointers.emplace_back(&highlight);
- }
-
- auto texture = texturePool.borrowTexture();
- LOG_ALWAYS_FATAL_IF(texture->get()->getBuffer()->initCheck() != OK);
-
- base::unique_fd bufferFence;
- if (texture->getReadyFence()) {
- // Bail out if the buffer is not ready, because there is some pending GPU work left.
- if (texture->getReadyFence()->getStatus() != Fence::Status::Signaled) {
- return;
- }
- bufferFence.reset(texture->getReadyFence()->dup());
- }
-
- base::unique_fd drawFence;
- status_t result =
- renderEngine.drawLayers(displaySettings, layerSettingsPointers, texture->get(), false,
- std::move(bufferFence), &drawFence);
-
- if (result == NO_ERROR) {
- mDrawFence = new Fence(drawFence.release());
- mOutputSpace = outputState.framebufferSpace;
- mTexture = texture;
- mTexture->setReadyFence(mDrawFence);
- mOutputSpace.orientation = outputState.framebufferSpace.orientation;
- mOutputDataspace = outputDataspace;
- mOrientation = orientation;
- mSkipCount = 0;
- } else {
- mTexture.reset();
- }
-}
-
-bool CachedSet::requiresHolePunch() const {
- // In order for the hole punch to be beneficial, the layer must be updating
- // regularly, meaning it should not have been merged with other layers.
- if (getLayerCount() != 1) {
- return false;
- }
-
- // There is no benefit to a hole punch unless the layer has a buffer.
- if (!mLayers[0].getBuffer()) {
- return false;
- }
-
- if (hasUnsupportedDataspace()) {
- return false;
- }
-
- const auto& layerFE = mLayers[0].getState()->getOutputLayer()->getLayerFE();
- if (layerFE.getCompositionState()->forceClientComposition) {
- return false;
- }
-
- return layerFE.hasRoundedCorners();
-}
-
-bool CachedSet::hasBlurBehind() const {
- return std::any_of(mLayers.cbegin(), mLayers.cend(),
- [](const Layer& layer) { return layer.getState()->hasBlurBehind(); });
-}
-
-namespace {
-bool contains(const Rect& outer, const Rect& inner) {
- return outer.left <= inner.left && outer.right >= inner.right && outer.top <= inner.top &&
- outer.bottom >= inner.bottom;
-}
-}; // namespace
-
-void CachedSet::addHolePunchLayerIfFeasible(const CachedSet& holePunchLayer, bool isFirstLayer) {
- // Verify that this CachedSet is opaque where the hole punch layer
- // will draw.
- const Rect& holePunchBounds = holePunchLayer.getBounds();
- for (const auto& layer : mLayers) {
- // The first layer is considered opaque because nothing is behind it.
- // Note that isOpaque is always false for a layer with rounded
- // corners, even if the interior is opaque. In theory, such a layer
- // could be used for a hole punch, but this is unlikely to happen in
- // practice.
- const auto* outputLayer = layer.getState()->getOutputLayer();
- if (contains(outputLayer->getState().displayFrame, holePunchBounds) &&
- (isFirstLayer || outputLayer->getLayerFE().getCompositionState()->isOpaque)) {
- mHolePunchLayer = holePunchLayer.getFirstLayer().getState();
- return;
- }
- }
-}
-
-void CachedSet::addBackgroundBlurLayer(const CachedSet& blurLayer) {
- mBlurLayer = blurLayer.getFirstLayer().getState();
-}
-
-compositionengine::OutputLayer* CachedSet::getHolePunchLayer() const {
- return mHolePunchLayer ? mHolePunchLayer->getOutputLayer() : nullptr;
-}
-
-compositionengine::OutputLayer* CachedSet::getBlurLayer() const {
- return mBlurLayer ? mBlurLayer->getOutputLayer() : nullptr;
-}
-
-bool CachedSet::hasUnsupportedDataspace() const {
- return std::any_of(mLayers.cbegin(), mLayers.cend(), [](const Layer& layer) {
- auto dataspace = layer.getState()->getDataspace();
- const auto transfer = static_cast<ui::Dataspace>(dataspace & ui::Dataspace::TRANSFER_MASK);
- if (transfer == ui::Dataspace::TRANSFER_ST2084 || transfer == ui::Dataspace::TRANSFER_HLG) {
- // Skip HDR.
- return true;
- }
-
- if ((dataspace & HAL_DATASPACE_STANDARD_MASK) == HAL_DATASPACE_STANDARD_BT601_625) {
- // RenderEngine does not match some DPUs, so skip
- // to avoid flickering/color differences.
- return true;
- }
- return false;
- });
-}
-
-bool CachedSet::hasProtectedLayers() const {
- return std::any_of(mLayers.cbegin(), mLayers.cend(),
- [](const Layer& layer) { return layer.getState()->isProtected(); });
-}
-
-void CachedSet::dump(std::string& result) const {
- const auto now = std::chrono::steady_clock::now();
-
- const auto lastUpdate =
- std::chrono::duration_cast<std::chrono::milliseconds>(now - mLastUpdate);
- base::StringAppendF(&result, " + Fingerprint %016zx, last update %sago, age %zd\n",
- mFingerprint, durationString(lastUpdate).c_str(), mAge);
- {
- const auto b = mTexture ? mTexture->get()->getBuffer().get() : nullptr;
- base::StringAppendF(&result, " Override buffer: %p\n", b);
- }
- base::StringAppendF(&result, " HolePunchLayer: %p\n", mHolePunchLayer);
-
- if (mLayers.size() == 1) {
- base::StringAppendF(&result, " Layer [%s]\n", mLayers[0].getName().c_str());
- base::StringAppendF(&result, " Buffer %p", mLayers[0].getBuffer().get());
- base::StringAppendF(&result, " Protected [%s]",
- mLayers[0].getState()->isProtected() ? "true" : "false");
- } else {
- result.append(" Cached set of:");
- for (const Layer& layer : mLayers) {
- base::StringAppendF(&result, "\n Layer [%s]", layer.getName().c_str());
- base::StringAppendF(&result, "\n Protected [%s]",
- layer.getState()->isProtected() ? "true" : "false");
- }
- }
-
- base::StringAppendF(&result, "\n Creation cost: %zd", getCreationCost());
- base::StringAppendF(&result, "\n Display cost: %zd\n", getDisplayCost());
-}
-
-} // namespace android::compositionengine::impl::planner
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
deleted file mode 100644
index f033279caa..0000000000
--- a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
+++ /dev/null
@@ -1,545 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#undef LOG_TAG
-#define LOG_TAG "Planner"
-// #define LOG_NDEBUG 0
-#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-
-#include <android-base/properties.h>
-#include <compositionengine/impl/planner/Flattener.h>
-#include <compositionengine/impl/planner/LayerState.h>
-
-#include <gui/TraceUtils.h>
-
-using time_point = std::chrono::steady_clock::time_point;
-using namespace std::chrono_literals;
-
-namespace android::compositionengine::impl::planner {
-
-namespace {
-
-// True if the underlying layer stack is the same modulo state that would be expected to be
-// different like specific buffers, false otherwise.
-bool isSameStack(const std::vector<const LayerState*>& incomingLayers,
- const std::vector<CachedSet>& cachedSets) {
- std::vector<const LayerState*> existingLayers;
- for (auto& cachedSet : cachedSets) {
- for (auto& layer : cachedSet.getConstituentLayers()) {
- existingLayers.push_back(layer.getState());
- }
- }
-
- if (incomingLayers.size() != existingLayers.size()) {
- return false;
- }
-
- for (size_t i = 0; i < incomingLayers.size(); i++) {
- // Checking the IDs here is very strict, but we do this as otherwise we may mistakenly try
- // to access destroyed OutputLayers later on.
- if (incomingLayers[i]->getId() != existingLayers[i]->getId() ||
- incomingLayers[i]->getDifferingFields(*(existingLayers[i])) != LayerStateField::None) {
- return false;
- }
- }
- return true;
-}
-
-} // namespace
-
-Flattener::Flattener(
- renderengine::RenderEngine& renderEngine, bool enableHolePunch,
- std::optional<CachedSetRenderSchedulingTunables> cachedSetRenderSchedulingTunables)
- : mRenderEngine(renderEngine),
- mEnableHolePunch(enableHolePunch),
- mCachedSetRenderSchedulingTunables(cachedSetRenderSchedulingTunables),
- mTexturePool(mRenderEngine) {
- const int timeoutInMs =
- base::GetIntProperty(std::string("debug.sf.layer_caching_active_layer_timeout_ms"), 0);
- if (timeoutInMs != 0) {
- mActiveLayerTimeout = std::chrono::milliseconds(timeoutInMs);
- }
-}
-
-NonBufferHash Flattener::flattenLayers(const std::vector<const LayerState*>& layers,
- NonBufferHash hash, time_point now) {
- ATRACE_CALL();
- const size_t unflattenedDisplayCost = calculateDisplayCost(layers);
- mUnflattenedDisplayCost += unflattenedDisplayCost;
-
- // We invalidate the layer cache if:
- // 1. We're not tracking any layers, or
- // 2. The last seen hashed geometry changed between frames, or
- // 3. A stricter equality check demonstrates that the layer stack really did change, since the
- // hashed geometry does not guarantee uniqueness.
- if (mCurrentGeometry != hash || (!mLayers.empty() && !isSameStack(layers, mLayers))) {
- resetActivities(hash, now);
- mFlattenedDisplayCost += unflattenedDisplayCost;
- return hash;
- }
-
- ++mInitialLayerCounts[layers.size()];
-
- // Only buildCachedSets if these layers are already stored in mLayers.
- // Otherwise (i.e. mergeWithCachedSets returns false), the time has not
- // changed, so buildCachedSets will never find any runs.
- const bool alreadyHadCachedSets = mergeWithCachedSets(layers, now);
-
- ++mFinalLayerCounts[mLayers.size()];
-
- if (alreadyHadCachedSets) {
- buildCachedSets(now);
- hash = computeLayersHash();
- }
-
- return hash;
-}
-
-void Flattener::renderCachedSets(
- const OutputCompositionState& outputState,
- std::optional<std::chrono::steady_clock::time_point> renderDeadline) {
- ATRACE_CALL();
-
- if (!mNewCachedSet) {
- return;
- }
-
- // Ensure that a cached set has a valid buffer first
- if (mNewCachedSet->hasRenderedBuffer()) {
- ATRACE_NAME("mNewCachedSet->hasRenderedBuffer()");
- return;
- }
-
- const auto now = std::chrono::steady_clock::now();
-
- // If we have a render deadline, and the flattener is configured to skip rendering if we don't
- // have enough time, then we skip rendering the cached set if we think that we'll steal too much
- // time from the next frame.
- if (renderDeadline && mCachedSetRenderSchedulingTunables) {
- if (const auto estimatedRenderFinish =
- now + mCachedSetRenderSchedulingTunables->cachedSetRenderDuration;
- estimatedRenderFinish > *renderDeadline) {
- mNewCachedSet->incrementSkipCount();
-
- if (mNewCachedSet->getSkipCount() <=
- mCachedSetRenderSchedulingTunables->maxDeferRenderAttempts) {
- ATRACE_FORMAT("DeadlinePassed: exceeded deadline by: %d us",
- std::chrono::duration_cast<std::chrono::microseconds>(
- estimatedRenderFinish - *renderDeadline)
- .count());
- return;
- } else {
- ATRACE_NAME("DeadlinePassed: exceeded max skips");
- }
- }
- }
-
- mNewCachedSet->render(mRenderEngine, mTexturePool, outputState);
-}
-
-void Flattener::dumpLayers(std::string& result) const {
- result.append(" Current layers:");
- for (const CachedSet& layer : mLayers) {
- result.append("\n");
- layer.dump(result);
- }
-}
-
-void Flattener::dump(std::string& result) const {
- const auto now = std::chrono::steady_clock::now();
-
- base::StringAppendF(&result, "Flattener state:\n");
-
- result.append("\n Statistics:\n");
-
- result.append(" Display cost (in screen-size buffers):\n");
- const size_t displayArea = static_cast<size_t>(mDisplaySize.width * mDisplaySize.height);
- base::StringAppendF(&result, " Unflattened: %.2f\n",
- static_cast<float>(mUnflattenedDisplayCost) / displayArea);
- base::StringAppendF(&result, " Flattened: %.2f\n",
- static_cast<float>(mFlattenedDisplayCost) / displayArea);
-
- const auto compareLayerCounts = [](const std::pair<size_t, size_t>& left,
- const std::pair<size_t, size_t>& right) {
- return left.first < right.first;
- };
-
- const size_t maxLayerCount = mInitialLayerCounts.empty()
- ? 0u
- : std::max_element(mInitialLayerCounts.cbegin(), mInitialLayerCounts.cend(),
- compareLayerCounts)
- ->first;
-
- result.append("\n Initial counts:\n");
- for (size_t count = 1; count < maxLayerCount; ++count) {
- size_t initial = mInitialLayerCounts.count(count) > 0 ? mInitialLayerCounts.at(count) : 0;
- base::StringAppendF(&result, " % 2zd: %zd\n", count, initial);
- }
-
- result.append("\n Final counts:\n");
- for (size_t count = 1; count < maxLayerCount; ++count) {
- size_t final = mFinalLayerCounts.count(count) > 0 ? mFinalLayerCounts.at(count) : 0;
- base::StringAppendF(&result, " % 2zd: %zd\n", count, final);
- }
-
- base::StringAppendF(&result, "\n Cached sets created: %zd\n", mCachedSetCreationCount);
- base::StringAppendF(&result, " Cost: %.2f\n",
- static_cast<float>(mCachedSetCreationCost) / displayArea);
-
- const auto lastUpdate =
- std::chrono::duration_cast<std::chrono::milliseconds>(now - mLastGeometryUpdate);
- base::StringAppendF(&result, "\n Current hash %016zx, last update %sago\n\n", mCurrentGeometry,
- durationString(lastUpdate).c_str());
-
- dumpLayers(result);
-}
-
-size_t Flattener::calculateDisplayCost(const std::vector<const LayerState*>& layers) const {
- Region coveredRegion;
- size_t displayCost = 0;
- bool hasClientComposition = false;
-
- for (const LayerState* layer : layers) {
- coveredRegion.orSelf(layer->getDisplayFrame());
-
- // Regardless of composition type, we always have to read each input once
- displayCost += static_cast<size_t>(layer->getDisplayFrame().width() *
- layer->getDisplayFrame().height());
-
- hasClientComposition |= layer->getCompositionType() == hal::Composition::CLIENT;
- }
-
- if (hasClientComposition) {
- // If there is client composition, the client target buffer has to be both written by the
- // GPU and read by the DPU, so we pay its cost twice
- displayCost += 2 *
- static_cast<size_t>(coveredRegion.bounds().width() *
- coveredRegion.bounds().height());
- }
-
- return displayCost;
-}
-
-void Flattener::resetActivities(NonBufferHash hash, time_point now) {
- ALOGV("[%s]", __func__);
-
- mCurrentGeometry = hash;
- mLastGeometryUpdate = now;
-
- for (const CachedSet& cachedSet : mLayers) {
- if (cachedSet.getLayerCount() > 1) {
- ++mInvalidatedCachedSetAges[cachedSet.getAge()];
- }
- }
-
- mLayers.clear();
-
- if (mNewCachedSet) {
- ++mInvalidatedCachedSetAges[mNewCachedSet->getAge()];
- mNewCachedSet = std::nullopt;
- }
-}
-
-NonBufferHash Flattener::computeLayersHash() const{
- size_t hash = 0;
- for (const auto& layer : mLayers) {
- android::hashCombineSingleHashed(hash, layer.getNonBufferHash());
- }
- return hash;
-}
-
-// Only called if the geometry matches the last frame. Return true if mLayers
-// was already populated with these layers, i.e. on the second and following
-// calls with the same geometry.
-bool Flattener::mergeWithCachedSets(const std::vector<const LayerState*>& layers, time_point now) {
- ATRACE_CALL();
- std::vector<CachedSet> merged;
-
- if (mLayers.empty()) {
- merged.reserve(layers.size());
- for (const LayerState* layer : layers) {
- merged.emplace_back(layer, now);
- mFlattenedDisplayCost += merged.back().getDisplayCost();
- }
- mLayers = std::move(merged);
- return false;
- }
-
- // the compiler should strip out the following no-op loops when ALOGV is off
- ALOGV("[%s] Incoming layers:", __func__);
- for (const LayerState* layer : layers) {
- ALOGV("%s", layer->getName().c_str());
- }
-
- ALOGV("[%s] Current layers:", __func__);
- for (const CachedSet& layer : mLayers) {
- const auto dumper = [&] {
- std::string dump;
- layer.dump(dump);
- return dump;
- };
- ALOGV("%s", dumper().c_str());
- }
-
- auto currentLayerIter = mLayers.begin();
- auto incomingLayerIter = layers.begin();
-
- // If not null, this represents the layer that is blurring the layer before
- // currentLayerIter. The blurring was stored in the override buffer, so the
- // layer that requests the blur no longer needs to do any blurring.
- compositionengine::OutputLayer* priorBlurLayer = nullptr;
-
- while (incomingLayerIter != layers.end()) {
- if (mNewCachedSet &&
- mNewCachedSet->getFirstLayer().getState()->getId() == (*incomingLayerIter)->getId()) {
- if (mNewCachedSet->hasBufferUpdate()) {
- ALOGV("[%s] Dropping new cached set", __func__);
- ++mInvalidatedCachedSetAges[0];
- mNewCachedSet = std::nullopt;
- } else if (mNewCachedSet->hasReadyBuffer()) {
- ALOGV("[%s] Found ready buffer", __func__);
- size_t skipCount = mNewCachedSet->getLayerCount();
- while (skipCount != 0) {
- auto* peekThroughLayer = mNewCachedSet->getHolePunchLayer();
- const size_t layerCount = currentLayerIter->getLayerCount();
- for (size_t i = 0; i < layerCount; ++i) {
- bool disableBlur = priorBlurLayer &&
- priorBlurLayer == (*incomingLayerIter)->getOutputLayer();
- OutputLayer::CompositionState& state =
- (*incomingLayerIter)->getOutputLayer()->editState();
- state.overrideInfo = {
- .buffer = mNewCachedSet->getBuffer(),
- .acquireFence = mNewCachedSet->getDrawFence(),
- .displayFrame = mNewCachedSet->getTextureBounds(),
- .dataspace = mNewCachedSet->getOutputDataspace(),
- .displaySpace = mNewCachedSet->getOutputSpace(),
- .damageRegion = Region::INVALID_REGION,
- .visibleRegion = mNewCachedSet->getVisibleRegion(),
- .peekThroughLayer = peekThroughLayer,
- .disableBackgroundBlur = disableBlur,
- };
- ++incomingLayerIter;
- }
-
- if (currentLayerIter->getLayerCount() > 1) {
- ++mInvalidatedCachedSetAges[currentLayerIter->getAge()];
- }
- ++currentLayerIter;
-
- skipCount -= layerCount;
- }
- priorBlurLayer = mNewCachedSet->getBlurLayer();
- merged.emplace_back(std::move(*mNewCachedSet));
- mNewCachedSet = std::nullopt;
- continue;
- }
- }
-
- if (!currentLayerIter->hasBufferUpdate()) {
- currentLayerIter->incrementAge();
- merged.emplace_back(*currentLayerIter);
-
- // Skip the incoming layers corresponding to this valid current layer
- const size_t layerCount = currentLayerIter->getLayerCount();
- auto* peekThroughLayer = currentLayerIter->getHolePunchLayer();
- for (size_t i = 0; i < layerCount; ++i) {
- bool disableBlur =
- priorBlurLayer && priorBlurLayer == (*incomingLayerIter)->getOutputLayer();
- OutputLayer::CompositionState& state =
- (*incomingLayerIter)->getOutputLayer()->editState();
- state.overrideInfo = {
- .buffer = currentLayerIter->getBuffer(),
- .acquireFence = currentLayerIter->getDrawFence(),
- .displayFrame = currentLayerIter->getTextureBounds(),
- .dataspace = currentLayerIter->getOutputDataspace(),
- .displaySpace = currentLayerIter->getOutputSpace(),
- .damageRegion = Region(),
- .visibleRegion = currentLayerIter->getVisibleRegion(),
- .peekThroughLayer = peekThroughLayer,
- .disableBackgroundBlur = disableBlur,
- };
- ++incomingLayerIter;
- }
- } else if (currentLayerIter->getLayerCount() > 1) {
- // Break the current layer into its constituent layers
- ++mInvalidatedCachedSetAges[currentLayerIter->getAge()];
- for (CachedSet& layer : currentLayerIter->decompose()) {
- bool disableBlur =
- priorBlurLayer && priorBlurLayer == (*incomingLayerIter)->getOutputLayer();
- OutputLayer::CompositionState& state =
- (*incomingLayerIter)->getOutputLayer()->editState();
- state.overrideInfo.disableBackgroundBlur = disableBlur;
- layer.updateAge(now);
- merged.emplace_back(layer);
- ++incomingLayerIter;
- }
- } else {
- bool disableBlur =
- priorBlurLayer && priorBlurLayer == (*incomingLayerIter)->getOutputLayer();
- OutputLayer::CompositionState& state =
- (*incomingLayerIter)->getOutputLayer()->editState();
- state.overrideInfo.disableBackgroundBlur = disableBlur;
- currentLayerIter->updateAge(now);
- merged.emplace_back(*currentLayerIter);
- ++incomingLayerIter;
- }
- priorBlurLayer = currentLayerIter->getBlurLayer();
- ++currentLayerIter;
- }
-
- for (const CachedSet& layer : merged) {
- mFlattenedDisplayCost += layer.getDisplayCost();
- }
-
- mLayers = std::move(merged);
- return true;
-}
-
-std::vector<Flattener::Run> Flattener::findCandidateRuns(time_point now) const {
- ATRACE_CALL();
- std::vector<Run> runs;
- bool isPartOfRun = false;
- Run::Builder builder;
- bool firstLayer = true;
- bool runHasFirstLayer = false;
-
- for (auto currentSet = mLayers.cbegin(); currentSet != mLayers.cend(); ++currentSet) {
- const bool layerIsInactive = now - currentSet->getLastUpdate() > mActiveLayerTimeout;
- const bool layerHasBlur = currentSet->hasBlurBehind();
- if (layerIsInactive && (firstLayer || runHasFirstLayer || !layerHasBlur) &&
- !currentSet->hasUnsupportedDataspace()) {
- if (isPartOfRun) {
- builder.append(currentSet->getLayerCount());
- } else {
- // Runs can't start with a non-buffer layer
- if (currentSet->getFirstLayer().getBuffer() == nullptr) {
- ALOGV("[%s] Skipping initial non-buffer layer", __func__);
- } else {
- builder.init(currentSet);
- if (firstLayer) {
- runHasFirstLayer = true;
- }
- isPartOfRun = true;
- }
- }
- } else if (isPartOfRun) {
- builder.setHolePunchCandidate(&(*currentSet));
-
- // If we're here then this blur layer recently had an active buffer updating, meaning
- // that there is exactly one layer. Blur radius currently is part of layer stack
- // geometry, so we're also guaranteed that the background blur radius hasn't changed for
- // at least as long as this new inactive cached set.
- if (runHasFirstLayer && layerHasBlur &&
- currentSet->getFirstLayer().getBackgroundBlurRadius() > 0) {
- builder.setBlurringLayer(&(*currentSet));
- }
- if (auto run = builder.validateAndBuild(); run) {
- runs.push_back(*run);
- }
-
- runHasFirstLayer = false;
- builder.reset();
- isPartOfRun = false;
- }
-
- firstLayer = false;
- }
-
- // If we're in the middle of a run at the end, we still need to validate and build it.
- if (isPartOfRun) {
- if (auto run = builder.validateAndBuild(); run) {
- runs.push_back(*run);
- }
- }
-
- ALOGV("[%s] Found %zu candidate runs", __func__, runs.size());
-
- return runs;
-}
-
-std::optional<Flattener::Run> Flattener::findBestRun(std::vector<Flattener::Run>& runs) const {
- if (runs.empty()) {
- return std::nullopt;
- }
-
- // TODO (b/181192467): Choose the best run, instead of just the first.
- return runs[0];
-}
-
-void Flattener::buildCachedSets(time_point now) {
- ATRACE_CALL();
- if (mLayers.empty()) {
- ALOGV("[%s] No layers found, returning", __func__);
- return;
- }
-
- // Don't try to build a new cached set if we already have a new one in progress
- if (mNewCachedSet) {
- return;
- }
-
- for (const CachedSet& layer : mLayers) {
- // TODO (b/191997217): make it less aggressive, and sync with findCandidateRuns
- if (layer.hasProtectedLayers()) {
- ATRACE_NAME("layer->hasProtectedLayers()");
- return;
- }
- }
-
- std::vector<Run> runs = findCandidateRuns(now);
-
- std::optional<Run> bestRun = findBestRun(runs);
-
- if (!bestRun) {
- return;
- }
-
- mNewCachedSet.emplace(*bestRun->getStart());
- mNewCachedSet->setLastUpdate(now);
- auto currentSet = bestRun->getStart();
- while (mNewCachedSet->getLayerCount() < bestRun->getLayerLength()) {
- ++currentSet;
- mNewCachedSet->append(*currentSet);
- }
-
- if (bestRun->getBlurringLayer()) {
- mNewCachedSet->addBackgroundBlurLayer(*bestRun->getBlurringLayer());
- }
-
- if (mEnableHolePunch && bestRun->getHolePunchCandidate() &&
- bestRun->getHolePunchCandidate()->requiresHolePunch()) {
- // Add the pip layer to mNewCachedSet, but in a special way - it should
- // replace the buffer with a clear round rect.
- mNewCachedSet->addHolePunchLayerIfFeasible(*bestRun->getHolePunchCandidate(),
- bestRun->getStart() == mLayers.cbegin());
- }
-
- // TODO(b/181192467): Actually compute new LayerState vector and corresponding hash for each run
- // and feedback into the predictor
-
- ++mCachedSetCreationCount;
- mCachedSetCreationCost += mNewCachedSet->getCreationCost();
-
- // note the compiler should strip the follow no-op statements when ALOGV is off
- const auto dumper = [&] {
- std::string setDump;
- mNewCachedSet->dump(setDump);
- return setDump;
- };
- ALOGV("[%s] Added new cached set:\n%s", __func__, dumper().c_str());
-}
-
-} // namespace android::compositionengine::impl::planner
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp b/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp
deleted file mode 100644
index 936dba3b29..0000000000
--- a/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <compositionengine/impl/planner/LayerState.h>
-
-namespace {
-extern "C" const char* __attribute__((unused)) __asan_default_options() {
- return "detect_container_overflow=0";
-}
-} // namespace
-
-namespace android::compositionengine::impl::planner {
-
-LayerState::LayerState(compositionengine::OutputLayer* layer)
- : mOutputLayer(layer),
- mColorTransform({[](auto layer) {
- const auto state = layer->getLayerFE().getCompositionState();
- return state->colorTransformIsIdentity ? mat4{}
- : state->colorTransform;
- },
- [](const mat4& mat) {
- using namespace std::string_literals;
- std::vector<std::string> split =
- base::Split(std::string(mat.asString().string()), "\n"s);
- split.pop_back(); // Strip the last (empty) line
- return split;
- }}) {
- update(layer);
-}
-
-Flags<LayerStateField> LayerState::update(compositionengine::OutputLayer* layer) {
- ALOGE_IF(mOutputLayer != layer && layer->getLayerFE().getSequence() != mId.get(),
- "[%s] Expected mOutputLayer ID to never change: %d, %d", __func__,
- layer->getLayerFE().getSequence(), mId.get());
-
- // It's possible for the OutputLayer pointer to change even when the layer is logically the
- // same, i.e., the LayerFE is the same. An example use-case is screen rotation.
- mOutputLayer = layer;
-
- Flags<LayerStateField> differences;
-
- // Update the unique fields as well, since we have to set them at least
- // once from the OutputLayer
- differences |= mId.update(layer);
- differences |= mName.update(layer);
-
- for (StateInterface* field : getNonUniqueFields()) {
- differences |= field->update(layer);
- }
-
- return differences;
-}
-
-size_t LayerState::getHash() const {
- size_t hash = 0;
- for (const StateInterface* field : getNonUniqueFields()) {
- if (field->getField() == LayerStateField::Buffer) {
- continue;
- }
- android::hashCombineSingleHashed(hash, field->getHash());
- }
-
- return hash;
-}
-
-Flags<LayerStateField> LayerState::getDifferingFields(const LayerState& other) const {
- Flags<LayerStateField> differences;
- auto myFields = getNonUniqueFields();
- auto otherFields = other.getNonUniqueFields();
- for (size_t i = 0; i < myFields.size(); ++i) {
- if (myFields[i]->getField() == LayerStateField::Buffer) {
- continue;
- }
-
- differences |= myFields[i]->getFieldIfDifferent(otherFields[i]);
- }
-
- return differences;
-}
-
-void LayerState::dump(std::string& result) const {
- for (const StateInterface* field : getNonUniqueFields()) {
- if (auto viewOpt = flag_name(field->getField()); viewOpt) {
- base::StringAppendF(&result, " %16s: ", std::string(*viewOpt).c_str());
- } else {
- result.append("<UNKNOWN FIELD>:\n");
- }
-
- bool first = true;
- for (const std::string& line : field->toStrings()) {
- base::StringAppendF(&result, "%s%s\n", first ? "" : " ",
- line.c_str());
- first = false;
- }
- }
- result.append("\n");
-}
-
-std::optional<std::string> LayerState::compare(const LayerState& other) const {
- std::string result;
-
- const auto& thisFields = getNonUniqueFields();
- const auto& otherFields = other.getNonUniqueFields();
- for (size_t f = 0; f < thisFields.size(); ++f) {
- const auto& thisField = thisFields[f];
- const auto& otherField = otherFields[f];
- // Skip comparing buffers
- if (thisField->getField() == LayerStateField::Buffer) {
- continue;
- }
-
- if (thisField->equals(otherField)) {
- continue;
- }
-
- if (auto viewOpt = flag_name(thisField->getField()); viewOpt) {
- base::StringAppendF(&result, " %16s: ", std::string(*viewOpt).c_str());
- } else {
- result.append("<UNKNOWN FIELD>:\n");
- }
-
- const auto& thisStrings = thisField->toStrings();
- const auto& otherStrings = otherField->toStrings();
- bool first = true;
- for (size_t line = 0; line < std::max(thisStrings.size(), otherStrings.size()); ++line) {
- if (!first) {
- result.append(" ");
- }
- first = false;
-
- if (line < thisStrings.size()) {
- base::StringAppendF(&result, "%-48.48s", thisStrings[line].c_str());
- } else {
- result.append(" ");
- }
-
- if (line < otherStrings.size()) {
- base::StringAppendF(&result, "%-48.48s", otherStrings[line].c_str());
- } else {
- result.append(" ");
- }
- result.append("\n");
- }
- }
-
- return result.empty() ? std::nullopt : std::make_optional(result);
-}
-
-bool operator==(const LayerState& lhs, const LayerState& rhs) {
- return lhs.mId == rhs.mId && lhs.mName == rhs.mName && lhs.mDisplayFrame == rhs.mDisplayFrame &&
- lhs.mSourceCrop == rhs.mSourceCrop && lhs.mBufferTransform == rhs.mBufferTransform &&
- lhs.mBlendMode == rhs.mBlendMode && lhs.mAlpha == rhs.mAlpha &&
- lhs.mLayerMetadata == rhs.mLayerMetadata && lhs.mVisibleRegion == rhs.mVisibleRegion &&
- lhs.mOutputDataspace == rhs.mOutputDataspace && lhs.mPixelFormat == rhs.mPixelFormat &&
- lhs.mColorTransform == rhs.mColorTransform &&
- lhs.mCompositionType == rhs.mCompositionType &&
- lhs.mSidebandStream == rhs.mSidebandStream && lhs.mBuffer == rhs.mBuffer &&
- (lhs.mCompositionType.get() != hal::Composition::SOLID_COLOR ||
- lhs.mSolidColor == rhs.mSolidColor);
-}
-
-NonBufferHash getNonBufferHash(const std::vector<const LayerState*>& layers) {
- size_t hash = 0;
- for (const auto layer : layers) {
- android::hashCombineSingleHashed(hash, layer->getHash());
- }
-
- return hash;
-}
-
-} // namespace android::compositionengine::impl::planner
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp
deleted file mode 100644
index f077470c80..0000000000
--- a/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp
+++ /dev/null
@@ -1,336 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// #define LOG_NDEBUG 0
-
-#undef LOG_TAG
-#define LOG_TAG "Planner"
-#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-
-#include <android-base/properties.h>
-#include <compositionengine/LayerFECompositionState.h>
-#include <compositionengine/impl/OutputLayerCompositionState.h>
-#include <compositionengine/impl/planner/Planner.h>
-
-#include <utils/Trace.h>
-#include <chrono>
-
-namespace android::compositionengine::impl::planner {
-
-namespace {
-
-std::optional<Flattener::CachedSetRenderSchedulingTunables> buildFlattenerTuneables() {
- if (!base::GetBoolProperty(std::string("debug.sf.enable_cached_set_render_scheduling"), true)) {
- return std::nullopt;
- }
-
- auto renderDuration = std::chrono::nanoseconds(
- base::GetUintProperty<uint64_t>(std::string("debug.sf.cached_set_render_duration_ns"),
- Flattener::CachedSetRenderSchedulingTunables::
- kDefaultCachedSetRenderDuration.count()));
-
- auto maxDeferRenderAttempts = base::GetUintProperty<
- size_t>(std::string("debug.sf.cached_set_max_defer_render_attmpts"),
- Flattener::CachedSetRenderSchedulingTunables::kDefaultMaxDeferRenderAttempts);
-
- return std::make_optional<Flattener::CachedSetRenderSchedulingTunables>(
- Flattener::CachedSetRenderSchedulingTunables{
- .cachedSetRenderDuration = renderDuration,
- .maxDeferRenderAttempts = maxDeferRenderAttempts,
- });
-}
-
-} // namespace
-
-Planner::Planner(renderengine::RenderEngine& renderEngine)
- // Implicitly, layer caching must also be enabled for the hole punch or
- // predictor to have any effect.
- // E.g., setprop debug.sf.enable_layer_caching 1, or
- // adb shell service call SurfaceFlinger 1040 i32 1 [i64 <display ID>]
- : mFlattener(renderEngine,
- base::GetBoolProperty(std::string("debug.sf.enable_hole_punch_pip"), true),
- buildFlattenerTuneables()) {
- mPredictorEnabled =
- base::GetBoolProperty(std::string("debug.sf.enable_planner_prediction"), false);
-}
-
-void Planner::setDisplaySize(ui::Size size) {
- mFlattener.setDisplaySize(size);
-}
-
-void Planner::plan(
- compositionengine::Output::OutputLayersEnumerator<compositionengine::Output>&& layers) {
- ATRACE_CALL();
- std::unordered_set<LayerId> removedLayers;
- removedLayers.reserve(mPreviousLayers.size());
-
- std::transform(mPreviousLayers.begin(), mPreviousLayers.end(),
- std::inserter(removedLayers, removedLayers.begin()),
- [](const auto& layer) { return layer.first; });
-
- std::vector<LayerId> currentLayerIds;
- for (auto layer : layers) {
- LayerId id = layer->getLayerFE().getSequence();
- if (const auto layerEntry = mPreviousLayers.find(id); layerEntry != mPreviousLayers.end()) {
- // Track changes from previous info
- LayerState& state = layerEntry->second;
- Flags<LayerStateField> differences = state.update(layer);
- if (differences.get() == 0) {
- state.incrementFramesSinceBufferUpdate();
- } else {
- ALOGV("Layer %s changed: %s", state.getName().c_str(),
- differences.string().c_str());
-
- if (differences.test(LayerStateField::Buffer)) {
- state.resetFramesSinceBufferUpdate();
- } else {
- state.incrementFramesSinceBufferUpdate();
- }
- }
- } else {
- LayerState state(layer);
- ALOGV("Added layer %s", state.getName().c_str());
- mPreviousLayers.emplace(std::make_pair(id, std::move(state)));
- }
-
- currentLayerIds.emplace_back(id);
-
- if (const auto found = removedLayers.find(id); found != removedLayers.end()) {
- removedLayers.erase(found);
- }
- }
-
- mCurrentLayers.clear();
- mCurrentLayers.reserve(currentLayerIds.size());
- std::transform(currentLayerIds.cbegin(), currentLayerIds.cend(),
- std::back_inserter(mCurrentLayers), [this](LayerId id) {
- LayerState* state = &mPreviousLayers.at(id);
- state->getOutputLayer()->editState().overrideInfo = {};
- return state;
- });
-
- const NonBufferHash hash = getNonBufferHash(mCurrentLayers);
- mFlattenedHash =
- mFlattener.flattenLayers(mCurrentLayers, hash, std::chrono::steady_clock::now());
- const bool layersWereFlattened = hash != mFlattenedHash;
-
- ALOGV("[%s] Initial hash %zx flattened hash %zx", __func__, hash, mFlattenedHash);
-
- if (mPredictorEnabled) {
- mPredictedPlan =
- mPredictor.getPredictedPlan(layersWereFlattened ? std::vector<const LayerState*>()
- : mCurrentLayers,
- mFlattenedHash);
- if (mPredictedPlan) {
- ALOGV("[%s] Predicting plan %s", __func__, to_string(mPredictedPlan->plan).c_str());
- } else {
- ALOGV("[%s] No prediction found\n", __func__);
- }
- }
-
- // Clean up the set of previous layers now that the view of the LayerStates in the flattener are
- // up-to-date.
- for (LayerId removedLayer : removedLayers) {
- if (const auto layerEntry = mPreviousLayers.find(removedLayer);
- layerEntry != mPreviousLayers.end()) {
- const auto& [id, state] = *layerEntry;
- ALOGV("Removed layer %s", state.getName().c_str());
- mPreviousLayers.erase(removedLayer);
- }
- }
-}
-
-void Planner::reportFinalPlan(
- compositionengine::Output::OutputLayersEnumerator<compositionengine::Output>&& layers) {
- ATRACE_CALL();
- if (!mPredictorEnabled) {
- return;
- }
-
- Plan finalPlan;
- const GraphicBuffer* currentOverrideBuffer = nullptr;
- bool hasSkippedLayers = false;
- for (auto layer : layers) {
- if (!layer->getState().overrideInfo.buffer) {
- continue;
- }
-
- const GraphicBuffer* overrideBuffer =
- layer->getState().overrideInfo.buffer->getBuffer().get();
- if (overrideBuffer != nullptr && overrideBuffer == currentOverrideBuffer) {
- // Skip this layer since it is part of a previous cached set
- hasSkippedLayers = true;
- continue;
- }
-
- currentOverrideBuffer = overrideBuffer;
-
- const bool forcedOrRequestedClient =
- layer->getState().forceClientComposition || layer->requiresClientComposition();
-
- finalPlan.addLayerType(
- forcedOrRequestedClient
- ? hardware::graphics::composer::hal::Composition::CLIENT
- : layer->getLayerFE().getCompositionState()->compositionType);
- }
-
- mPredictor.recordResult(mPredictedPlan, mFlattenedHash, mCurrentLayers, hasSkippedLayers,
- finalPlan);
-}
-
-void Planner::renderCachedSets(
- const OutputCompositionState& outputState,
- std::optional<std::chrono::steady_clock::time_point> renderDeadline) {
- ATRACE_CALL();
- mFlattener.renderCachedSets(outputState, renderDeadline);
-}
-
-void Planner::dump(const Vector<String16>& args, std::string& result) {
- if (args.size() > 1) {
- const String8 command(args[1]);
- if (command == "--compare" || command == "-c") {
- if (args.size() < 4) {
- base::StringAppendF(&result,
- "Expected two layer stack hashes, e.g. '--planner %s "
- "<left_hash> <right_hash>'\n",
- command.string());
- return;
- }
- if (args.size() > 4) {
- base::StringAppendF(&result,
- "Too many arguments found, expected '--planner %s <left_hash> "
- "<right_hash>'\n",
- command.string());
- return;
- }
-
- const String8 leftHashString(args[2]);
- size_t leftHash = 0;
- int fieldsRead = sscanf(leftHashString.string(), "%zx", &leftHash);
- if (fieldsRead != 1) {
- base::StringAppendF(&result, "Failed to parse %s as a size_t\n",
- leftHashString.string());
- return;
- }
-
- const String8 rightHashString(args[3]);
- size_t rightHash = 0;
- fieldsRead = sscanf(rightHashString.string(), "%zx", &rightHash);
- if (fieldsRead != 1) {
- base::StringAppendF(&result, "Failed to parse %s as a size_t\n",
- rightHashString.string());
- return;
- }
-
- if (mPredictorEnabled) {
- mPredictor.compareLayerStacks(leftHash, rightHash, result);
- }
- } else if (command == "--describe" || command == "-d") {
- if (args.size() < 3) {
- base::StringAppendF(&result,
- "Expected a layer stack hash, e.g. '--planner %s <hash>'\n",
- command.string());
- return;
- }
- if (args.size() > 3) {
- base::StringAppendF(&result,
- "Too many arguments found, expected '--planner %s <hash>'\n",
- command.string());
- return;
- }
-
- const String8 hashString(args[2]);
- size_t hash = 0;
- const int fieldsRead = sscanf(hashString.string(), "%zx", &hash);
- if (fieldsRead != 1) {
- base::StringAppendF(&result, "Failed to parse %s as a size_t\n",
- hashString.string());
- return;
- }
-
- if (mPredictorEnabled) {
- mPredictor.describeLayerStack(hash, result);
- }
- } else if (command == "--help" || command == "-h") {
- dumpUsage(result);
- } else if (command == "--similar" || command == "-s") {
- if (args.size() < 3) {
- base::StringAppendF(&result, "Expected a plan string, e.g. '--planner %s <plan>'\n",
- command.string());
- return;
- }
- if (args.size() > 3) {
- base::StringAppendF(&result,
- "Too many arguments found, expected '--planner %s <plan>'\n",
- command.string());
- return;
- }
-
- const String8 planString(args[2]);
- std::optional<Plan> plan = Plan::fromString(std::string(planString.string()));
- if (!plan) {
- base::StringAppendF(&result, "Failed to parse %s as a Plan\n", planString.string());
- return;
- }
-
- if (mPredictorEnabled) {
- mPredictor.listSimilarStacks(*plan, result);
- }
- } else if (command == "--layers" || command == "-l") {
- mFlattener.dumpLayers(result);
- } else {
- base::StringAppendF(&result, "Unknown command '%s'\n\n", command.string());
- dumpUsage(result);
- }
- return;
- }
-
- // If there are no specific commands, dump the usual state
-
- mFlattener.dump(result);
- result.append("\n");
-
- if (mPredictorEnabled) {
- mPredictor.dump(result);
- }
-}
-
-void Planner::dumpUsage(std::string& result) const {
- result.append("Planner command line interface usage\n");
- result.append(" dumpsys SurfaceFlinger --planner <command> [arguments]\n\n");
-
- result.append("If run without a command, dumps current Planner state\n\n");
-
- result.append("Commands:\n");
-
- result.append("[--compare|-c] <left_hash> <right_hash>\n");
- result.append(" Compares the predictions <left_hash> and <right_hash> by showing differences"
- " in their example layer stacks\n");
-
- result.append("[--describe|-d] <hash>\n");
- result.append(" Prints the example layer stack and prediction statistics for <hash>\n");
-
- result.append("[--help|-h]\n");
- result.append(" Shows this message\n");
-
- result.append("[--similar|-s] <plan>\n");
- result.append(" Prints the example layer names for similar stacks matching <plan>\n");
-
- result.append("[--layers|-l]\n");
- result.append(" Prints the current layers\n");
-}
-
-} // namespace android::compositionengine::impl::planner
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Predictor.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Predictor.cpp
deleted file mode 100644
index 8226ef7b4c..0000000000
--- a/services/surfaceflinger/CompositionEngine/src/planner/Predictor.cpp
+++ /dev/null
@@ -1,481 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// #define LOG_NDEBUG 0
-
-#undef LOG_TAG
-#define LOG_TAG "Planner"
-
-#include <compositionengine/impl/planner/Predictor.h>
-
-namespace android::compositionengine::impl::planner {
-
-std::optional<LayerStack::ApproximateMatch> LayerStack::getApproximateMatch(
- const std::vector<const LayerState*>& other) const {
- // Differing numbers of layers are never an approximate match
- if (mLayers.size() != other.size()) {
- return std::nullopt;
- }
-
- std::optional<ApproximateMatch> approximateMatch = {};
- for (size_t i = 0; i < mLayers.size(); ++i) {
- // Skip identical layers
- if (mLayers[i].getHash() == other[i]->getHash()) {
- continue;
- }
-
- // Skip layers where both are client-composited, since that doesn't change the
- // composition plan
- if (mLayers[i].getCompositionType() == hal::Composition::CLIENT &&
- other[i]->getCompositionType() == hal::Composition::CLIENT) {
- continue;
- }
-
- // If layers differ in composition type, their stacks are too different
- if (mLayers[i].getCompositionType() != other[i]->getCompositionType()) {
- return std::nullopt;
- }
-
- // If layers are not identical, but we already detected a prior approximate match for a
- // previous layer, the LayerStacks differ by too much, so return nothing
- if (approximateMatch) {
- return std::nullopt;
- }
-
- Flags<LayerStateField> differingFields = mLayers[i].getDifferingFields(*other[i]);
-
- // If we don't find an approximate match on this layer, then the LayerStacks differ
- // by too much, so return nothing
- const int differingFieldCount = __builtin_popcount(differingFields.get());
- if (differingFieldCount <= kMaxDifferingFields) {
- approximateMatch = ApproximateMatch{
- .differingIndex = i,
- .differingFields = differingFields,
- };
- } else {
- return std::nullopt;
- }
- }
-
- if (approximateMatch) {
- return approximateMatch;
- }
-
- // If we make it through the layer-by-layer comparison without an approximate match,
- // it means that all layers were either identical or had client-composited layers in common,
- // which don't affect the composition strategy, so return a successful result with
- // no differences.
- return ApproximateMatch{
- .differingIndex = 0,
- .differingFields = {},
- };
-}
-
-std::optional<Plan> Plan::fromString(const std::string& string) {
- Plan plan;
- for (char c : string) {
- switch (c) {
- case 'C':
- plan.addLayerType(hal::Composition::CLIENT);
- continue;
- case 'U':
- plan.addLayerType(hal::Composition::CURSOR);
- continue;
- case 'D':
- plan.addLayerType(hal::Composition::DEVICE);
- continue;
- case 'I':
- plan.addLayerType(hal::Composition::INVALID);
- continue;
- case 'B':
- plan.addLayerType(hal::Composition::SIDEBAND);
- continue;
- case 'S':
- plan.addLayerType(hal::Composition::SOLID_COLOR);
- continue;
- default:
- return std::nullopt;
- }
- }
- return plan;
-}
-
-std::string to_string(const Plan& plan) {
- std::string result;
- for (auto type : plan.mLayerTypes) {
- switch (type) {
- case hal::Composition::CLIENT:
- result.append("C");
- break;
- case hal::Composition::CURSOR:
- result.append("U");
- break;
- case hal::Composition::DEVICE:
- result.append("D");
- break;
- case hal::Composition::INVALID:
- result.append("I");
- break;
- case hal::Composition::SIDEBAND:
- result.append("B");
- break;
- case hal::Composition::SOLID_COLOR:
- result.append("S");
- break;
- }
- }
- return result;
-}
-
-void Prediction::dump(std::string& result) const {
- result.append(to_string(mPlan));
- result.append(" [Exact ");
- mExactStats.dump(result);
- result.append("] [Approximate ");
- mApproximateStats.dump(result);
- result.append("]");
-}
-
-std::optional<Predictor::PredictedPlan> Predictor::getPredictedPlan(
- const std::vector<const LayerState*>& layers, NonBufferHash hash) const {
- // First check for an exact match
- if (std::optional<Plan> exactMatch = getExactMatch(hash); exactMatch) {
- ALOGV("[%s] Found an exact match for %zx", __func__, hash);
- return PredictedPlan{.hash = hash, .plan = *exactMatch, .type = Prediction::Type::Exact};
- }
-
- // If only a hash was passed in for a layer stack with a cached set, don't perform
- // approximate matches and return early
- if (layers.empty()) {
- ALOGV("[%s] Only hash was passed, but no exact match was found", __func__);
- return std::nullopt;
- }
-
- // Then check for approximate matches
- if (std::optional<NonBufferHash> approximateMatch = getApproximateMatch(layers);
- approximateMatch) {
- ALOGV("[%s] Found an approximate match for %zx", __func__, *approximateMatch);
- const Prediction& prediction = getPrediction(*approximateMatch);
- return PredictedPlan{.hash = *approximateMatch,
- .plan = prediction.getPlan(),
- .type = Prediction::Type::Approximate};
- }
-
- return std::nullopt;
-}
-
-void Predictor::recordResult(std::optional<PredictedPlan> predictedPlan,
- NonBufferHash flattenedHash,
- const std::vector<const LayerState*>& layers, bool hasSkippedLayers,
- Plan result) {
- if (predictedPlan) {
- recordPredictedResult(*predictedPlan, layers, std::move(result));
- return;
- }
-
- ++mMissCount;
-
- if (!hasSkippedLayers && findSimilarPrediction(layers, result)) {
- return;
- }
-
- ALOGV("[%s] Adding novel candidate %zx", __func__, flattenedHash);
- mCandidates.emplace_front(flattenedHash, Prediction(layers, result));
- if (mCandidates.size() > MAX_CANDIDATES) {
- mCandidates.pop_back();
- }
-}
-
-void Predictor::dump(std::string& result) const {
- result.append("Predictor state:\n");
-
- const size_t hitCount = mExactHitCount + mApproximateHitCount;
- const size_t totalAttempts = hitCount + mMissCount;
- base::StringAppendF(&result, "Global non-skipped hit rate: %.2f%% (%zd/%zd)\n",
- 100.0f * hitCount / totalAttempts, hitCount, totalAttempts);
- base::StringAppendF(&result, " Exact hits: %zd\n", mExactHitCount);
- base::StringAppendF(&result, " Approximate hits: %zd\n", mApproximateHitCount);
- base::StringAppendF(&result, " Misses: %zd\n\n", mMissCount);
-
- dumpPredictionsByFrequency(result);
-}
-
-void Predictor::compareLayerStacks(NonBufferHash leftHash, NonBufferHash rightHash,
- std::string& result) const {
- const auto& [leftPredictionEntry, rightPredictionEntry] =
- std::make_tuple(mPredictions.find(leftHash), mPredictions.find(rightHash));
- if (leftPredictionEntry == mPredictions.end()) {
- base::StringAppendF(&result, "No prediction found for %zx\n", leftHash);
- return;
- }
- if (rightPredictionEntry == mPredictions.end()) {
- base::StringAppendF(&result, "No prediction found for %zx\n", rightHash);
- return;
- }
-
- base::StringAppendF(&result,
- "Comparing %-16zx %-16zx\n",
- leftHash, rightHash);
-
- const auto& [leftPrediction, rightPrediction] =
- std::make_tuple(leftPredictionEntry->second, rightPredictionEntry->second);
- const auto& [leftStack, rightStack] = std::make_tuple(leftPrediction.getExampleLayerStack(),
- rightPrediction.getExampleLayerStack());
- leftStack.compare(rightStack, result);
-}
-
-void Predictor::describeLayerStack(NonBufferHash hash, std::string& result) const {
- base::StringAppendF(&result, "Describing %zx:\n\n", hash);
-
- if (const auto predictionsEntry = mPredictions.find(hash);
- predictionsEntry != mPredictions.cend()) {
- const auto& [hash, prediction] = *predictionsEntry;
-
- prediction.getExampleLayerStack().dump(result);
-
- result.append("Prediction: ");
- prediction.dump(result);
- result.append("\n");
- } else {
- result.append("No predictions found\n");
- }
-}
-
-void Predictor::listSimilarStacks(Plan plan, std::string& result) const {
- base::StringAppendF(&result, "Similar stacks for plan %s:\n", to_string(plan).c_str());
-
- if (const auto similarStacksEntry = mSimilarStacks.find(plan);
- similarStacksEntry != mSimilarStacks.end()) {
- const auto& [_, similarStacks] = *similarStacksEntry;
- for (NonBufferHash hash : similarStacks) {
- base::StringAppendF(&result, "\nPrediction hash %zx:\n", hash);
- const Prediction& prediction = mPredictions.at(hash);
- prediction.getExampleLayerStack().dumpLayerNames(result);
- }
- } else {
- result.append("No similar stacks found\n");
- }
-}
-
-const Prediction& Predictor::getPrediction(NonBufferHash hash) const {
- if (const auto predictionEntry = mPredictions.find(hash);
- predictionEntry != mPredictions.end()) {
- const auto& [_, prediction] = *predictionEntry;
- return prediction;
- } else {
- const auto candidateEntry = getCandidateEntryByHash(hash);
- ALOGE_IF(candidateEntry == mCandidates.cend(),
- "Hash should have been found in either predictions or candidates");
- const auto& [_, prediction] = *candidateEntry;
- return prediction;
- }
-}
-
-Prediction& Predictor::getPrediction(NonBufferHash hash) {
- return const_cast<Prediction&>(const_cast<const Predictor*>(this)->getPrediction(hash));
-}
-
-std::optional<Plan> Predictor::getExactMatch(NonBufferHash hash) const {
- const Prediction* match = nullptr;
- if (const auto predictionEntry = mPredictions.find(hash);
- predictionEntry != mPredictions.end()) {
- const auto& [hash, prediction] = *predictionEntry;
- match = &prediction;
- } else if (const auto candidateEntry = getCandidateEntryByHash(hash);
- candidateEntry != mCandidates.cend()) {
- match = &(candidateEntry->prediction);
- }
-
- if (match == nullptr) {
- return std::nullopt;
- }
-
- if (match->getMissCount(Prediction::Type::Exact) != 0) {
- ALOGV("[%s] Skipping exact match for %zx because of prior miss", __func__, hash);
- return std::nullopt;
- }
-
- return match->getPlan();
-}
-
-std::optional<NonBufferHash> Predictor::getApproximateMatch(
- const std::vector<const LayerState*>& layers) const {
- const auto approximateStackMatches = [&](const ApproximateStack& approximateStack) {
- const auto& exampleStack = mPredictions.at(approximateStack.hash).getExampleLayerStack();
- if (const auto approximateMatchOpt = exampleStack.getApproximateMatch(layers);
- approximateMatchOpt) {
- return *approximateMatchOpt == approximateStack.match;
- }
- return false;
- };
-
- const auto candidateMatches = [&](const PromotionCandidate& candidate) {
- ALOGV("[getApproximateMatch] checking against %zx", candidate.hash);
- return candidate.prediction.getExampleLayerStack().getApproximateMatch(layers) !=
- std::nullopt;
- };
-
- const Prediction* match = nullptr;
- NonBufferHash hash;
- if (const auto approximateStackIter =
- std::find_if(mApproximateStacks.cbegin(), mApproximateStacks.cend(),
- approximateStackMatches);
- approximateStackIter != mApproximateStacks.cend()) {
- match = &mPredictions.at(approximateStackIter->hash);
- hash = approximateStackIter->hash;
- } else if (const auto candidateEntry =
- std::find_if(mCandidates.cbegin(), mCandidates.cend(), candidateMatches);
- candidateEntry != mCandidates.cend()) {
- match = &(candidateEntry->prediction);
- hash = candidateEntry->hash;
- }
-
- if (match == nullptr) {
- return std::nullopt;
- }
-
- if (match->getMissCount(Prediction::Type::Approximate) != 0) {
- ALOGV("[%s] Skipping approximate match for %zx because of prior miss", __func__, hash);
- return std::nullopt;
- }
-
- return hash;
-}
-
-void Predictor::promoteIfCandidate(NonBufferHash predictionHash) {
- // Return if the candidate has already been promoted
- if (mPredictions.count(predictionHash) != 0) {
- return;
- }
-
- ALOGV("[%s] Promoting %zx from candidate to prediction", __func__, predictionHash);
-
- auto candidateEntry = getCandidateEntryByHash(predictionHash);
- ALOGE_IF(candidateEntry == mCandidates.end(), "Expected to find candidate");
-
- mSimilarStacks[candidateEntry->prediction.getPlan()].push_back(predictionHash);
- mPredictions.emplace(predictionHash, std::move(candidateEntry->prediction));
- mCandidates.erase(candidateEntry);
-}
-
-void Predictor::recordPredictedResult(PredictedPlan predictedPlan,
- const std::vector<const LayerState*>& layers, Plan result) {
- Prediction& prediction = getPrediction(predictedPlan.hash);
- if (prediction.getPlan() != result) {
- ALOGV("[%s] %s prediction missed, expected %s, found %s", __func__,
- to_string(predictedPlan.type).c_str(), to_string(prediction.getPlan()).c_str(),
- to_string(result).c_str());
- prediction.recordMiss(predictedPlan.type);
- ++mMissCount;
- return;
- }
-
- switch (predictedPlan.type) {
- case Prediction::Type::Approximate:
- ++mApproximateHitCount;
- break;
- case Prediction::Type::Exact:
- ++mExactHitCount;
- break;
- default:
- break;
- }
-
- ALOGV("[%s] %s prediction hit", __func__, to_string(predictedPlan.type).c_str());
- ALOGV("[%s] Plan: %s", __func__, to_string(result).c_str());
- prediction.recordHit(predictedPlan.type);
-
- const auto stackMatchesHash = [hash = predictedPlan.hash](const ApproximateStack& stack) {
- return stack.hash == hash;
- };
-
- if (predictedPlan.type == Prediction::Type::Approximate) {
- // If this approximate match is not already in the list of approximate stacks, add it
- if (std::find_if(mApproximateStacks.cbegin(), mApproximateStacks.cend(),
- stackMatchesHash) == mApproximateStacks.cend()) {
- ALOGV("[%s] Adding approximate match to list", __func__);
- const auto approximateMatchOpt =
- prediction.getExampleLayerStack().getApproximateMatch(layers);
- ALOGE_IF(!approximateMatchOpt, "Expected an approximate match");
- mApproximateStacks.emplace_back(predictedPlan.hash, *approximateMatchOpt);
- }
- }
-
- promoteIfCandidate(predictedPlan.hash);
-}
-
-bool Predictor::findSimilarPrediction(const std::vector<const LayerState*>& layers, Plan result) {
- const auto stacksEntry = mSimilarStacks.find(result);
- if (stacksEntry == mSimilarStacks.end()) {
- return false;
- }
-
- std::optional<ApproximateStack> bestMatch;
- const auto& [plan, similarStacks] = *stacksEntry;
- for (NonBufferHash hash : similarStacks) {
- const Prediction& prediction = mPredictions.at(hash);
- auto approximateMatch = prediction.getExampleLayerStack().getApproximateMatch(layers);
- if (!approximateMatch) {
- continue;
- }
-
- const int differingFieldCount = __builtin_popcount(approximateMatch->differingFields.get());
- if (!bestMatch ||
- differingFieldCount < __builtin_popcount(bestMatch->match.differingFields.get())) {
- bestMatch = {hash, *approximateMatch};
- }
- }
-
- if (!bestMatch) {
- return false;
- }
-
- ALOGV("[%s] Adding %zx to approximate stacks", __func__, bestMatch->hash);
-
- mApproximateStacks.emplace_back(*bestMatch);
- return true;
-}
-
-void Predictor::dumpPredictionsByFrequency(std::string& result) const {
- struct HashFrequency {
- HashFrequency(NonBufferHash hash, size_t totalAttempts)
- : hash(hash), totalAttempts(totalAttempts) {}
-
- NonBufferHash hash;
- size_t totalAttempts;
- };
-
- std::vector<HashFrequency> hashFrequencies;
- for (const auto& [hash, prediction] : mPredictions) {
- hashFrequencies.emplace_back(hash,
- prediction.getHitCount(Prediction::Type::Total) +
- prediction.getMissCount(Prediction::Type::Total));
- }
-
- std::sort(hashFrequencies.begin(), hashFrequencies.end(),
- [](const HashFrequency& lhs, const HashFrequency& rhs) {
- return lhs.totalAttempts > rhs.totalAttempts;
- });
-
- result.append("Predictions:\n");
- for (const auto& [hash, totalAttempts] : hashFrequencies) {
- base::StringAppendF(&result, " %016zx ", hash);
- mPredictions.at(hash).dump(result);
- result.append("\n");
- }
-}
-
-} // namespace android::compositionengine::impl::planner
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/TexturePool.cpp b/services/surfaceflinger/CompositionEngine/src/planner/TexturePool.cpp
deleted file mode 100644
index e3772a22d2..0000000000
--- a/services/surfaceflinger/CompositionEngine/src/planner/TexturePool.cpp
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// #define LOG_NDEBUG 0
-
-#undef LOG_TAG
-#define LOG_TAG "Planner"
-
-#include <compositionengine/impl/planner/TexturePool.h>
-#include <utils/Log.h>
-
-namespace android::compositionengine::impl::planner {
-
-void TexturePool::setDisplaySize(ui::Size size) {
- if (mSize == size) {
- return;
- }
- mSize = size;
- mPool.clear();
- mPool.resize(kMinPoolSize);
- std::generate_n(mPool.begin(), kMinPoolSize, [&]() { return Entry{genTexture(), nullptr}; });
-}
-
-std::shared_ptr<TexturePool::AutoTexture> TexturePool::borrowTexture() {
- if (mPool.empty()) {
- return std::make_shared<AutoTexture>(*this, genTexture(), nullptr);
- }
-
- const auto entry = mPool.front();
- mPool.pop_front();
- return std::make_shared<AutoTexture>(*this, entry.texture, entry.fence);
-}
-
-void TexturePool::returnTexture(std::shared_ptr<renderengine::ExternalTexture>&& texture,
- const sp<Fence>& fence) {
- // Drop the texture on the floor if the pool is no longer tracking textures of the same size.
- if (static_cast<int32_t>(texture->getBuffer()->getWidth()) != mSize.getWidth() ||
- static_cast<int32_t>(texture->getBuffer()->getHeight()) != mSize.getHeight()) {
- ALOGV("Deallocating texture from Planner's pool - display size changed (previous: (%dx%d), "
- "current: (%dx%d))",
- texture->getBuffer()->getWidth(), texture->getBuffer()->getHeight(), mSize.getWidth(),
- mSize.getHeight());
- return;
- }
-
- // Also ensure the pool does not grow beyond a maximum size.
- if (mPool.size() == kMaxPoolSize) {
- ALOGD("Deallocating texture from Planner's pool - max size [%" PRIu64 "] reached",
- static_cast<uint64_t>(kMaxPoolSize));
- return;
- }
-
- mPool.push_back({std::move(texture), fence});
-}
-
-std::shared_ptr<renderengine::ExternalTexture> TexturePool::genTexture() {
- LOG_ALWAYS_FATAL_IF(!mSize.isValid(), "Attempted to generate texture with invalid size");
- return std::make_shared<
- renderengine::ExternalTexture>(sp<GraphicBuffer>::
- make(mSize.getWidth(), mSize.getHeight(),
- HAL_PIXEL_FORMAT_RGBA_8888, 1,
- GraphicBuffer::USAGE_HW_RENDER |
- GraphicBuffer::USAGE_HW_COMPOSER |
- GraphicBuffer::USAGE_HW_TEXTURE,
- "Planner"),
- mRenderEngine,
- renderengine::ExternalTexture::Usage::READABLE |
- renderengine::ExternalTexture::Usage::WRITEABLE);
-}
-
-} // namespace android::compositionengine::impl::planner \ No newline at end of file