1 /*
2  * Copyright 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #undef LOG_TAG
18 #define LOG_TAG "Planner"
19 // #define LOG_NDEBUG 0
20 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
21 
22 #include <android-base/properties.h>
23 #include <android-base/stringprintf.h>
24 #include <compositionengine/impl/OutputCompositionState.h>
25 #include <compositionengine/impl/planner/CachedSet.h>
26 #include <math/HashCombine.h>
27 #include <renderengine/DisplaySettings.h>
28 #include <renderengine/RenderEngine.h>
29 #include <ui/DebugUtils.h>
30 #include <ui/HdrRenderTypeUtils.h>
31 #include <utils/Trace.h>
32 
33 namespace android::compositionengine::impl::planner {
34 
35 const bool CachedSet::sDebugHighlighLayers =
36         base::GetBoolProperty(std::string("debug.sf.layer_caching_highlight"), false);
37 
durationString(std::chrono::milliseconds duration)38 std::string durationString(std::chrono::milliseconds duration) {
39     using namespace std::chrono_literals;
40 
41     std::string result;
42 
43     if (duration >= 1h) {
44         const auto hours = std::chrono::duration_cast<std::chrono::hours>(duration);
45         base::StringAppendF(&result, "%d hr ", static_cast<int>(hours.count()));
46         duration -= hours;
47     }
48     if (duration >= 1min) {
49         const auto minutes = std::chrono::duration_cast<std::chrono::minutes>(duration);
50         base::StringAppendF(&result, "%d min ", static_cast<int>(minutes.count()));
51         duration -= minutes;
52     }
53     base::StringAppendF(&result, "%.3f sec ", duration.count() / 1000.0f);
54 
55     return result;
56 }
57 
Layer(const LayerState * state,std::chrono::steady_clock::time_point lastUpdate)58 CachedSet::Layer::Layer(const LayerState* state, std::chrono::steady_clock::time_point lastUpdate)
59       : mState(state), mHash(state->getHash()), mLastUpdate(lastUpdate) {}
60 
CachedSet(const LayerState * layer,std::chrono::steady_clock::time_point lastUpdate)61 CachedSet::CachedSet(const LayerState* layer, std::chrono::steady_clock::time_point lastUpdate)
62       : mFingerprint(layer->getHash()), mLastUpdate(lastUpdate) {
63     addLayer(layer, lastUpdate);
64 }
65 
CachedSet(Layer layer)66 CachedSet::CachedSet(Layer layer)
67       : mFingerprint(layer.getHash()),
68         mLastUpdate(layer.getLastUpdate()),
69         mBounds(layer.getDisplayFrame()),
70         mVisibleRegion(layer.getVisibleRegion()) {
71     mLayers.emplace_back(std::move(layer));
72 }
73 
addLayer(const LayerState * layer,std::chrono::steady_clock::time_point lastUpdate)74 void CachedSet::addLayer(const LayerState* layer,
75                          std::chrono::steady_clock::time_point lastUpdate) {
76     mLayers.emplace_back(layer, lastUpdate);
77 
78     Region boundingRegion;
79     boundingRegion.orSelf(mBounds);
80     boundingRegion.orSelf(layer->getDisplayFrame());
81     mBounds = boundingRegion.getBounds();
82     mVisibleRegion.orSelf(layer->getVisibleRegion());
83 }
84 
getNonBufferHash() const85 NonBufferHash CachedSet::getNonBufferHash() const {
86     if (mLayers.size() == 1) {
87         return mFingerprint;
88     }
89 
90     // TODO(b/182614524): We sometimes match this with LayerState hashes. Determine if that is
91     // necessary (and therefore we need to match implementations).
92     size_t hash = 0;
93     android::hashCombineSingle(hash, mBounds);
94     android::hashCombineSingle(hash, mOutputDataspace);
95     android::hashCombineSingle(hash, mOrientation);
96     return hash;
97 }
98 
getComponentDisplayCost() const99 size_t CachedSet::getComponentDisplayCost() const {
100     size_t displayCost = 0;
101 
102     for (const Layer& layer : mLayers) {
103         displayCost += static_cast<size_t>(layer.getDisplayFrame().width() *
104                                            layer.getDisplayFrame().height());
105     }
106 
107     return displayCost;
108 }
109 
getCreationCost() const110 size_t CachedSet::getCreationCost() const {
111     if (mLayers.size() == 1) {
112         return 0;
113     }
114 
115     // Reads
116     size_t creationCost = getComponentDisplayCost();
117 
118     // Write - assumes that the output buffer only gets written once per pixel
119     creationCost += static_cast<size_t>(mBounds.width() * mBounds.height());
120 
121     return creationCost;
122 }
123 
getDisplayCost() const124 size_t CachedSet::getDisplayCost() const {
125     return static_cast<size_t>(mBounds.width() * mBounds.height());
126 }
127 
hasBufferUpdate() const128 bool CachedSet::hasBufferUpdate() const {
129     for (const Layer& layer : mLayers) {
130         if (layer.getFramesSinceBufferUpdate() == 0) {
131             return true;
132         }
133     }
134     return false;
135 }
136 
hasReadyBuffer() const137 bool CachedSet::hasReadyBuffer() const {
138     return mTexture && mDrawFence->getStatus() == Fence::Status::Signaled;
139 }
140 
decompose() const141 std::vector<CachedSet> CachedSet::decompose() const {
142     std::vector<CachedSet> layers;
143 
144     std::transform(mLayers.begin(), mLayers.end(), std::back_inserter(layers),
145                    [](Layer layer) { return CachedSet(std::move(layer)); });
146 
147     return layers;
148 }
149 
updateAge(std::chrono::steady_clock::time_point now)150 void CachedSet::updateAge(std::chrono::steady_clock::time_point now) {
151     LOG_ALWAYS_FATAL_IF(mLayers.size() > 1, "[%s] This should only be called on single-layer sets",
152                         __func__);
153 
154     if (mLayers[0].getFramesSinceBufferUpdate() == 0) {
155         mLastUpdate = now;
156         mAge = 0;
157     }
158 }
159 
render(renderengine::RenderEngine & renderEngine,TexturePool & texturePool,const OutputCompositionState & outputState,bool deviceHandlesColorTransform)160 void CachedSet::render(renderengine::RenderEngine& renderEngine, TexturePool& texturePool,
161                        const OutputCompositionState& outputState,
162                        bool deviceHandlesColorTransform) {
163     ATRACE_CALL();
164     if (outputState.powerCallback) {
165         outputState.powerCallback->notifyCpuLoadUp();
166     }
167     const Rect& viewport = outputState.layerStackSpace.getContent();
168     const ui::Dataspace& outputDataspace = outputState.dataspace;
169     const ui::Transform::RotationFlags orientation =
170             ui::Transform::toRotationFlags(outputState.framebufferSpace.getOrientation());
171 
172     renderengine::DisplaySettings displaySettings{
173             .physicalDisplay = outputState.framebufferSpace.getContent(),
174             .clip = viewport,
175             .outputDataspace = outputDataspace,
176             .colorTransform = outputState.colorTransformMatrix,
177             .deviceHandlesColorTransform = deviceHandlesColorTransform,
178             .orientation = orientation,
179             .targetLuminanceNits = outputState.displayBrightnessNits,
180     };
181 
182     LayerFE::ClientCompositionTargetSettings
183             targetSettings{.clip = Region(viewport),
184                            .needsFiltering = false,
185                            .isSecure = outputState.isSecure,
186                            .isProtected = false,
187                            .viewport = viewport,
188                            .dataspace = outputDataspace,
189                            .realContentIsVisible = true,
190                            .clearContent = false,
191                            .blurSetting =
192                                    LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled,
193                            .whitePointNits = outputState.displayBrightnessNits,
194                            .treat170mAsSrgb = outputState.treat170mAsSrgb};
195 
196     std::vector<renderengine::LayerSettings> layerSettings;
197     renderengine::LayerSettings highlight;
198     for (const auto& layer : mLayers) {
199         if (auto clientCompositionSettings =
200                     layer.getState()->getOutputLayer()->getLayerFE().prepareClientComposition(
201                             targetSettings)) {
202             layerSettings.push_back(std::move(*clientCompositionSettings));
203         }
204     }
205 
206     renderengine::LayerSettings blurLayerSettings;
207     if (mBlurLayer) {
208         auto blurSettings = targetSettings;
209         blurSettings.blurSetting =
210                 LayerFE::ClientCompositionTargetSettings::BlurSetting::BackgroundBlurOnly;
211 
212         auto blurLayerSettings =
213                 mBlurLayer->getOutputLayer()->getLayerFE().prepareClientComposition(blurSettings);
214         // This mimics Layer::prepareClearClientComposition
215         blurLayerSettings->skipContentDraw = true;
216         blurLayerSettings->name = std::string("blur layer");
217         // Clear out the shadow settings
218         blurLayerSettings->shadow = {};
219         layerSettings.push_back(std::move(*blurLayerSettings));
220     }
221 
222     if (mHolePunchLayer) {
223         auto& layerFE = mHolePunchLayer->getOutputLayer()->getLayerFE();
224 
225         auto holePunchSettings = layerFE.prepareClientComposition(targetSettings);
226         // This mimics Layer::prepareClearClientComposition
227         holePunchSettings->source.buffer.buffer = nullptr;
228         holePunchSettings->source.solidColor = half3(0.0f, 0.0f, 0.0f);
229         holePunchSettings->disableBlending = true;
230         holePunchSettings->alpha = 0.0f;
231         holePunchSettings->name =
232                 android::base::StringPrintf("hole punch layer for %s", layerFE.getDebugName());
233 
234         // Add a solid background as the first layer in case there is no opaque
235         // buffer behind the punch hole
236         renderengine::LayerSettings holePunchBackgroundSettings;
237         holePunchBackgroundSettings.alpha = 1.0f;
238         holePunchBackgroundSettings.name = std::string("holePunchBackground");
239         holePunchBackgroundSettings.geometry.boundaries = holePunchSettings->geometry.boundaries;
240         holePunchBackgroundSettings.geometry.positionTransform =
241                 holePunchSettings->geometry.positionTransform;
242         layerSettings.emplace(layerSettings.begin(), std::move(holePunchBackgroundSettings));
243 
244         layerSettings.push_back(std::move(*holePunchSettings));
245     }
246 
247     if (sDebugHighlighLayers) {
248         highlight = {
249                 .geometry =
250                         renderengine::Geometry{
251                                 .boundaries = FloatRect(0.0f, 0.0f,
252                                                         static_cast<float>(mBounds.getWidth()),
253                                                         static_cast<float>(mBounds.getHeight())),
254                         },
255                 .source =
256                         renderengine::PixelSource{
257                                 .solidColor = half3(0.25f, 0.0f, 0.5f),
258                         },
259                 .alpha = half(0.05f),
260         };
261 
262         layerSettings.emplace_back(highlight);
263     }
264 
265     auto texture = texturePool.borrowTexture();
266     LOG_ALWAYS_FATAL_IF(texture->get()->getBuffer()->initCheck() != OK);
267 
268     base::unique_fd bufferFence;
269     if (texture->getReadyFence()) {
270         // Bail out if the buffer is not ready, because there is some pending GPU work left.
271         if (texture->getReadyFence()->getStatus() != Fence::Status::Signaled) {
272             return;
273         }
274         bufferFence.reset(texture->getReadyFence()->dup());
275     }
276 
277     auto fenceResult = renderEngine
278                                .drawLayers(displaySettings, layerSettings, texture->get(),
279                                            std::move(bufferFence))
280                                .get();
281 
282     if (fenceStatus(fenceResult) == NO_ERROR) {
283         mDrawFence = std::move(fenceResult).value_or(Fence::NO_FENCE);
284         mOutputSpace = outputState.framebufferSpace;
285         mTexture = texture;
286         mTexture->setReadyFence(mDrawFence);
287         mOutputSpace.setOrientation(outputState.framebufferSpace.getOrientation());
288         mOutputDataspace = outputDataspace;
289         mOrientation = orientation;
290         mSkipCount = 0;
291     } else {
292         mTexture.reset();
293     }
294 }
295 
requiresHolePunch() const296 bool CachedSet::requiresHolePunch() const {
297     // In order for the hole punch to be beneficial, the layer must be updating
298     // regularly, meaning  it should not have been merged with other layers.
299     if (getLayerCount() != 1) {
300         return false;
301     }
302 
303     // There is no benefit to a hole punch unless the layer has a buffer.
304     if (!mLayers[0].getBuffer()) {
305         return false;
306     }
307 
308     if (hasKnownColorShift()) {
309         return false;
310     }
311 
312     const auto& layerFE = mLayers[0].getState()->getOutputLayer()->getLayerFE();
313     const auto* compositionState = layerFE.getCompositionState();
314     if (compositionState->forceClientComposition) {
315         return false;
316     }
317 
318     if (compositionState->blendMode != hal::BlendMode::NONE) {
319         return false;
320     }
321 
322     return layerFE.hasRoundedCorners();
323 }
324 
hasBlurBehind() const325 bool CachedSet::hasBlurBehind() const {
326     return std::any_of(mLayers.cbegin(), mLayers.cend(),
327                        [](const Layer& layer) { return layer.getState()->hasBlurBehind(); });
328 }
329 
330 namespace {
contains(const Rect & outer,const Rect & inner)331 bool contains(const Rect& outer, const Rect& inner) {
332     return outer.left <= inner.left && outer.right >= inner.right && outer.top <= inner.top &&
333             outer.bottom >= inner.bottom;
334 }
335 }; // namespace
336 
addHolePunchLayerIfFeasible(const CachedSet & holePunchLayer,bool isFirstLayer)337 void CachedSet::addHolePunchLayerIfFeasible(const CachedSet& holePunchLayer, bool isFirstLayer) {
338     // Verify that this CachedSet is opaque where the hole punch layer
339     // will draw.
340     const Rect& holePunchBounds = holePunchLayer.getBounds();
341     for (const auto& layer : mLayers) {
342         // The first layer is considered opaque because nothing is behind it.
343         // Note that isOpaque is always false for a layer with rounded
344         // corners, even if the interior is opaque. In theory, such a layer
345         // could be used for a hole punch, but this is unlikely to happen in
346         // practice.
347         const auto* outputLayer = layer.getState()->getOutputLayer();
348         if (contains(outputLayer->getState().displayFrame, holePunchBounds) &&
349             (isFirstLayer || outputLayer->getLayerFE().getCompositionState()->isOpaque)) {
350             mHolePunchLayer = holePunchLayer.getFirstLayer().getState();
351             return;
352         }
353     }
354 }
355 
addBackgroundBlurLayer(const CachedSet & blurLayer)356 void CachedSet::addBackgroundBlurLayer(const CachedSet& blurLayer) {
357     mBlurLayer = blurLayer.getFirstLayer().getState();
358 }
359 
getHolePunchLayer() const360 compositionengine::OutputLayer* CachedSet::getHolePunchLayer() const {
361     return mHolePunchLayer ? mHolePunchLayer->getOutputLayer() : nullptr;
362 }
363 
getBlurLayer() const364 compositionengine::OutputLayer* CachedSet::getBlurLayer() const {
365     return mBlurLayer ? mBlurLayer->getOutputLayer() : nullptr;
366 }
367 
hasKnownColorShift() const368 bool CachedSet::hasKnownColorShift() const {
369     return std::any_of(mLayers.cbegin(), mLayers.cend(), [](const Layer& layer) {
370         auto dataspace = layer.getState()->getDataspace();
371 
372         // Layers are never dimmed when rendering a cached set, meaning that we may ask HWC to
373         // dim a cached set. But this means that we can never cache any HDR layers so that we
374         // don't accidentally dim those layers.
375         const auto hdrType = getHdrRenderType(dataspace, layer.getState()->getPixelFormat(),
376                                               layer.getState()->getHdrSdrRatio());
377         if (hdrType != HdrRenderType::SDR) {
378             return true;
379         }
380 
381         // Layers that have dimming disabled pretend that they're HDR.
382         if (!layer.getState()->isDimmingEnabled()) {
383             return true;
384         }
385 
386         if ((dataspace & HAL_DATASPACE_STANDARD_MASK) == HAL_DATASPACE_STANDARD_BT601_625) {
387             // RenderEngine does not match some DPUs, so skip
388             // to avoid flickering/color differences.
389             return true;
390         }
391         return false;
392     });
393 }
394 
hasProtectedLayers() const395 bool CachedSet::hasProtectedLayers() const {
396     return std::any_of(mLayers.cbegin(), mLayers.cend(),
397                        [](const Layer& layer) { return layer.getState()->isProtected(); });
398 }
399 
cachingHintExcludesLayers() const400 bool CachedSet::cachingHintExcludesLayers() const {
401     const bool shouldExcludeLayers =
402             std::any_of(mLayers.cbegin(), mLayers.cend(), [](const Layer& layer) {
403                 return layer.getState()->getCachingHint() == gui::CachingHint::Disabled;
404             });
405 
406     LOG_ALWAYS_FATAL_IF(shouldExcludeLayers && getLayerCount() > 1,
407                         "CachedSet is invalid: should be excluded but contains %zu layers",
408                         getLayerCount());
409     return shouldExcludeLayers;
410 }
411 
dump(std::string & result) const412 void CachedSet::dump(std::string& result) const {
413     const auto now = std::chrono::steady_clock::now();
414 
415     const auto lastUpdate =
416             std::chrono::duration_cast<std::chrono::milliseconds>(now - mLastUpdate);
417     base::StringAppendF(&result, "  + Fingerprint %016zx, last update %sago, age %zd\n",
418                         mFingerprint, durationString(lastUpdate).c_str(), mAge);
419     {
420         const auto b = mTexture ? mTexture->get()->getBuffer().get() : nullptr;
421         base::StringAppendF(&result, "    Override buffer: %p\n", b);
422     }
423     base::StringAppendF(&result, "    HolePunchLayer: %p\t%s\n", mHolePunchLayer,
424                         mHolePunchLayer
425                                 ? mHolePunchLayer->getOutputLayer()->getLayerFE().getDebugName()
426                                 : "");
427 
428     if (mLayers.size() == 1) {
429         base::StringAppendF(&result, "    Layer [%s]\n", mLayers[0].getName().c_str());
430         if (const sp<GraphicBuffer> buffer = mLayers[0].getState()->getBuffer().promote()) {
431             base::StringAppendF(&result, "    Buffer %p", buffer.get());
432             base::StringAppendF(&result, "    Format %s",
433                                 decodePixelFormat(buffer->getPixelFormat()).c_str());
434         }
435         base::StringAppendF(&result, "    Protected [%s]\n",
436                             mLayers[0].getState()->isProtected() ? "true" : "false");
437     } else {
438         result.append("    Cached set of:\n");
439         for (const Layer& layer : mLayers) {
440             base::StringAppendF(&result, "      Layer [%s]\n", layer.getName().c_str());
441             if (const sp<GraphicBuffer> buffer = layer.getState()->getBuffer().promote()) {
442                 base::StringAppendF(&result, "       Buffer %p", buffer.get());
443                 base::StringAppendF(&result, "    Format[%s]",
444                                     decodePixelFormat(buffer->getPixelFormat()).c_str());
445             }
446             base::StringAppendF(&result, "       Protected [%s]\n",
447                                 layer.getState()->isProtected() ? "true" : "false");
448         }
449     }
450 
451     base::StringAppendF(&result, "    Creation cost: %zd\n", getCreationCost());
452     base::StringAppendF(&result, "    Display cost: %zd\n", getDisplayCost());
453 }
454 
455 } // namespace android::compositionengine::impl::planner
456