• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <utils/Trace.h>
31 
32 #include <utils/Trace.h>
33 
34 namespace android::compositionengine::impl::planner {
35 
36 const bool CachedSet::sDebugHighlighLayers =
37         base::GetBoolProperty(std::string("debug.sf.layer_caching_highlight"), false);
38 
durationString(std::chrono::milliseconds duration)39 std::string durationString(std::chrono::milliseconds duration) {
40     using namespace std::chrono_literals;
41 
42     std::string result;
43 
44     if (duration >= 1h) {
45         const auto hours = std::chrono::duration_cast<std::chrono::hours>(duration);
46         base::StringAppendF(&result, "%d hr ", static_cast<int>(hours.count()));
47         duration -= hours;
48     }
49     if (duration >= 1min) {
50         const auto minutes = std::chrono::duration_cast<std::chrono::minutes>(duration);
51         base::StringAppendF(&result, "%d min ", static_cast<int>(minutes.count()));
52         duration -= minutes;
53     }
54     base::StringAppendF(&result, "%.3f sec ", duration.count() / 1000.0f);
55 
56     return result;
57 }
58 
Layer(const LayerState * state,std::chrono::steady_clock::time_point lastUpdate)59 CachedSet::Layer::Layer(const LayerState* state, std::chrono::steady_clock::time_point lastUpdate)
60       : mState(state), mHash(state->getHash()), mLastUpdate(lastUpdate) {}
61 
CachedSet(const LayerState * layer,std::chrono::steady_clock::time_point lastUpdate)62 CachedSet::CachedSet(const LayerState* layer, std::chrono::steady_clock::time_point lastUpdate)
63       : mFingerprint(layer->getHash()), mLastUpdate(lastUpdate) {
64     addLayer(layer, lastUpdate);
65 }
66 
CachedSet(Layer layer)67 CachedSet::CachedSet(Layer layer)
68       : mFingerprint(layer.getHash()),
69         mLastUpdate(layer.getLastUpdate()),
70         mBounds(layer.getDisplayFrame()),
71         mVisibleRegion(layer.getVisibleRegion()) {
72     mLayers.emplace_back(std::move(layer));
73 }
74 
addLayer(const LayerState * layer,std::chrono::steady_clock::time_point lastUpdate)75 void CachedSet::addLayer(const LayerState* layer,
76                          std::chrono::steady_clock::time_point lastUpdate) {
77     mLayers.emplace_back(layer, lastUpdate);
78 
79     Region boundingRegion;
80     boundingRegion.orSelf(mBounds);
81     boundingRegion.orSelf(layer->getDisplayFrame());
82     mBounds = boundingRegion.getBounds();
83     mVisibleRegion.orSelf(layer->getVisibleRegion());
84 }
85 
getNonBufferHash() const86 NonBufferHash CachedSet::getNonBufferHash() const {
87     if (mLayers.size() == 1) {
88         return mFingerprint;
89     }
90 
91     // TODO(b/182614524): We sometimes match this with LayerState hashes. Determine if that is
92     // necessary (and therefore we need to match implementations).
93     size_t hash = 0;
94     android::hashCombineSingle(hash, mBounds);
95     android::hashCombineSingle(hash, mOutputDataspace);
96     android::hashCombineSingle(hash, mOrientation);
97     return hash;
98 }
99 
getComponentDisplayCost() const100 size_t CachedSet::getComponentDisplayCost() const {
101     size_t displayCost = 0;
102 
103     for (const Layer& layer : mLayers) {
104         displayCost += static_cast<size_t>(layer.getDisplayFrame().width() *
105                                            layer.getDisplayFrame().height());
106     }
107 
108     return displayCost;
109 }
110 
getCreationCost() const111 size_t CachedSet::getCreationCost() const {
112     if (mLayers.size() == 1) {
113         return 0;
114     }
115 
116     // Reads
117     size_t creationCost = getComponentDisplayCost();
118 
119     // Write - assumes that the output buffer only gets written once per pixel
120     creationCost += static_cast<size_t>(mBounds.width() * mBounds.height());
121 
122     return creationCost;
123 }
124 
getDisplayCost() const125 size_t CachedSet::getDisplayCost() const {
126     return static_cast<size_t>(mBounds.width() * mBounds.height());
127 }
128 
hasBufferUpdate() const129 bool CachedSet::hasBufferUpdate() const {
130     for (const Layer& layer : mLayers) {
131         if (layer.getFramesSinceBufferUpdate() == 0) {
132             return true;
133         }
134     }
135     return false;
136 }
137 
hasReadyBuffer() const138 bool CachedSet::hasReadyBuffer() const {
139     return mTexture && mDrawFence->getStatus() == Fence::Status::Signaled;
140 }
141 
decompose() const142 std::vector<CachedSet> CachedSet::decompose() const {
143     std::vector<CachedSet> layers;
144 
145     std::transform(mLayers.begin(), mLayers.end(), std::back_inserter(layers),
146                    [](Layer layer) { return CachedSet(std::move(layer)); });
147 
148     return layers;
149 }
150 
updateAge(std::chrono::steady_clock::time_point now)151 void CachedSet::updateAge(std::chrono::steady_clock::time_point now) {
152     LOG_ALWAYS_FATAL_IF(mLayers.size() > 1, "[%s] This should only be called on single-layer sets",
153                         __func__);
154 
155     if (mLayers[0].getFramesSinceBufferUpdate() == 0) {
156         mLastUpdate = now;
157         mAge = 0;
158     }
159 }
160 
render(renderengine::RenderEngine & renderEngine,TexturePool & texturePool,const OutputCompositionState & outputState,bool deviceHandlesColorTransform)161 void CachedSet::render(renderengine::RenderEngine& renderEngine, TexturePool& texturePool,
162                        const OutputCompositionState& outputState,
163                        bool deviceHandlesColorTransform) {
164     ATRACE_CALL();
165     if (outputState.powerCallback) {
166         outputState.powerCallback->notifyCpuLoadUp();
167     }
168     const Rect& viewport = outputState.layerStackSpace.getContent();
169     const ui::Dataspace& outputDataspace = outputState.dataspace;
170     const ui::Transform::RotationFlags orientation =
171             ui::Transform::toRotationFlags(outputState.framebufferSpace.getOrientation());
172 
173     renderengine::DisplaySettings displaySettings{
174             .physicalDisplay = outputState.framebufferSpace.getContent(),
175             .clip = viewport,
176             .outputDataspace = outputDataspace,
177             .colorTransform = outputState.colorTransformMatrix,
178             .deviceHandlesColorTransform = deviceHandlesColorTransform,
179             .orientation = orientation,
180             .targetLuminanceNits = outputState.displayBrightnessNits,
181     };
182 
183     LayerFE::ClientCompositionTargetSettings
184             targetSettings{.clip = Region(viewport),
185                            .needsFiltering = false,
186                            .isSecure = outputState.isSecure,
187                            .supportsProtectedContent = false,
188                            .viewport = viewport,
189                            .dataspace = outputDataspace,
190                            .realContentIsVisible = true,
191                            .clearContent = false,
192                            .blurSetting =
193                                    LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled,
194                            .whitePointNits = outputState.displayBrightnessNits,
195                            .treat170mAsSrgb = outputState.treat170mAsSrgb};
196 
197     std::vector<renderengine::LayerSettings> layerSettings;
198     renderengine::LayerSettings highlight;
199     for (const auto& layer : mLayers) {
200         if (auto clientCompositionSettings =
201                     layer.getState()->getOutputLayer()->getLayerFE().prepareClientComposition(
202                             targetSettings)) {
203             layerSettings.push_back(std::move(*clientCompositionSettings));
204         }
205     }
206 
207     renderengine::LayerSettings blurLayerSettings;
208     if (mBlurLayer) {
209         auto blurSettings = targetSettings;
210         blurSettings.blurSetting =
211                 LayerFE::ClientCompositionTargetSettings::BlurSetting::BackgroundBlurOnly;
212 
213         auto blurLayerSettings =
214                 mBlurLayer->getOutputLayer()->getLayerFE().prepareClientComposition(blurSettings);
215         // This mimics Layer::prepareClearClientComposition
216         blurLayerSettings->skipContentDraw = true;
217         blurLayerSettings->name = std::string("blur layer");
218         // Clear out the shadow settings
219         blurLayerSettings->shadow = {};
220         layerSettings.push_back(std::move(*blurLayerSettings));
221     }
222 
223     if (mHolePunchLayer) {
224         auto& layerFE = mHolePunchLayer->getOutputLayer()->getLayerFE();
225 
226         auto holePunchSettings = layerFE.prepareClientComposition(targetSettings);
227         // This mimics Layer::prepareClearClientComposition
228         holePunchSettings->source.buffer.buffer = nullptr;
229         holePunchSettings->source.solidColor = half3(0.0f, 0.0f, 0.0f);
230         holePunchSettings->disableBlending = true;
231         holePunchSettings->alpha = 0.0f;
232         holePunchSettings->name =
233                 android::base::StringPrintf("hole punch layer for %s", layerFE.getDebugName());
234 
235         // Add a solid background as the first layer in case there is no opaque
236         // buffer behind the punch hole
237         renderengine::LayerSettings holePunchBackgroundSettings;
238         holePunchBackgroundSettings.alpha = 1.0f;
239         holePunchBackgroundSettings.name = std::string("holePunchBackground");
240         holePunchBackgroundSettings.geometry.boundaries = holePunchSettings->geometry.boundaries;
241         holePunchBackgroundSettings.geometry.positionTransform =
242                 holePunchSettings->geometry.positionTransform;
243         layerSettings.emplace(layerSettings.begin(), std::move(holePunchBackgroundSettings));
244 
245         layerSettings.push_back(std::move(*holePunchSettings));
246     }
247 
248     if (sDebugHighlighLayers) {
249         highlight = {
250                 .geometry =
251                         renderengine::Geometry{
252                                 .boundaries = FloatRect(0.0f, 0.0f,
253                                                         static_cast<float>(mBounds.getWidth()),
254                                                         static_cast<float>(mBounds.getHeight())),
255                         },
256                 .source =
257                         renderengine::PixelSource{
258                                 .solidColor = half3(0.25f, 0.0f, 0.5f),
259                         },
260                 .alpha = half(0.05f),
261         };
262 
263         layerSettings.emplace_back(highlight);
264     }
265 
266     auto texture = texturePool.borrowTexture();
267     LOG_ALWAYS_FATAL_IF(texture->get()->getBuffer()->initCheck() != OK);
268 
269     base::unique_fd bufferFence;
270     if (texture->getReadyFence()) {
271         // Bail out if the buffer is not ready, because there is some pending GPU work left.
272         if (texture->getReadyFence()->getStatus() != Fence::Status::Signaled) {
273             return;
274         }
275         bufferFence.reset(texture->getReadyFence()->dup());
276     }
277 
278     constexpr bool kUseFramebufferCache = false;
279 
280     auto fenceResult = renderEngine
281                                .drawLayers(displaySettings, layerSettings, texture->get(),
282                                            kUseFramebufferCache, std::move(bufferFence))
283                                .get();
284 
285     if (fenceStatus(fenceResult) == NO_ERROR) {
286         mDrawFence = std::move(fenceResult).value_or(Fence::NO_FENCE);
287         mOutputSpace = outputState.framebufferSpace;
288         mTexture = texture;
289         mTexture->setReadyFence(mDrawFence);
290         mOutputSpace.setOrientation(outputState.framebufferSpace.getOrientation());
291         mOutputDataspace = outputDataspace;
292         mOrientation = orientation;
293         mSkipCount = 0;
294     } else {
295         mTexture.reset();
296     }
297 }
298 
requiresHolePunch() const299 bool CachedSet::requiresHolePunch() const {
300     // In order for the hole punch to be beneficial, the layer must be updating
301     // regularly, meaning  it should not have been merged with other layers.
302     if (getLayerCount() != 1) {
303         return false;
304     }
305 
306     // There is no benefit to a hole punch unless the layer has a buffer.
307     if (!mLayers[0].getBuffer()) {
308         return false;
309     }
310 
311     if (hasUnsupportedDataspace()) {
312         return false;
313     }
314 
315     const auto& layerFE = mLayers[0].getState()->getOutputLayer()->getLayerFE();
316     const auto* compositionState = layerFE.getCompositionState();
317     if (compositionState->forceClientComposition) {
318         return false;
319     }
320 
321     if (compositionState->blendMode != hal::BlendMode::NONE) {
322         return false;
323     }
324 
325     return layerFE.hasRoundedCorners();
326 }
327 
hasBlurBehind() const328 bool CachedSet::hasBlurBehind() const {
329     return std::any_of(mLayers.cbegin(), mLayers.cend(),
330                        [](const Layer& layer) { return layer.getState()->hasBlurBehind(); });
331 }
332 
333 namespace {
contains(const Rect & outer,const Rect & inner)334 bool contains(const Rect& outer, const Rect& inner) {
335     return outer.left <= inner.left && outer.right >= inner.right && outer.top <= inner.top &&
336             outer.bottom >= inner.bottom;
337 }
338 }; // namespace
339 
addHolePunchLayerIfFeasible(const CachedSet & holePunchLayer,bool isFirstLayer)340 void CachedSet::addHolePunchLayerIfFeasible(const CachedSet& holePunchLayer, bool isFirstLayer) {
341     // Verify that this CachedSet is opaque where the hole punch layer
342     // will draw.
343     const Rect& holePunchBounds = holePunchLayer.getBounds();
344     for (const auto& layer : mLayers) {
345         // The first layer is considered opaque because nothing is behind it.
346         // Note that isOpaque is always false for a layer with rounded
347         // corners, even if the interior is opaque. In theory, such a layer
348         // could be used for a hole punch, but this is unlikely to happen in
349         // practice.
350         const auto* outputLayer = layer.getState()->getOutputLayer();
351         if (contains(outputLayer->getState().displayFrame, holePunchBounds) &&
352             (isFirstLayer || outputLayer->getLayerFE().getCompositionState()->isOpaque)) {
353             mHolePunchLayer = holePunchLayer.getFirstLayer().getState();
354             return;
355         }
356     }
357 }
358 
addBackgroundBlurLayer(const CachedSet & blurLayer)359 void CachedSet::addBackgroundBlurLayer(const CachedSet& blurLayer) {
360     mBlurLayer = blurLayer.getFirstLayer().getState();
361 }
362 
getHolePunchLayer() const363 compositionengine::OutputLayer* CachedSet::getHolePunchLayer() const {
364     return mHolePunchLayer ? mHolePunchLayer->getOutputLayer() : nullptr;
365 }
366 
getBlurLayer() const367 compositionengine::OutputLayer* CachedSet::getBlurLayer() const {
368     return mBlurLayer ? mBlurLayer->getOutputLayer() : nullptr;
369 }
370 
hasUnsupportedDataspace() const371 bool CachedSet::hasUnsupportedDataspace() const {
372     return std::any_of(mLayers.cbegin(), mLayers.cend(), [](const Layer& layer) {
373         auto dataspace = layer.getState()->getDataspace();
374         const auto transfer = static_cast<ui::Dataspace>(dataspace & ui::Dataspace::TRANSFER_MASK);
375         if (transfer == ui::Dataspace::TRANSFER_ST2084 || transfer == ui::Dataspace::TRANSFER_HLG) {
376             // Skip HDR.
377             return true;
378         }
379 
380         if ((dataspace & HAL_DATASPACE_STANDARD_MASK) == HAL_DATASPACE_STANDARD_BT601_625) {
381             // RenderEngine does not match some DPUs, so skip
382             // to avoid flickering/color differences.
383             return true;
384         }
385         // TODO(b/274804887): temp fix of overdimming issue, skip caching if hsdr/sdr ratio > 1.01f
386         if (layer.getState()->getHdrSdrRatio() > 1.01f) {
387             return true;
388         }
389         return false;
390     });
391 }
392 
hasProtectedLayers() const393 bool CachedSet::hasProtectedLayers() const {
394     return std::any_of(mLayers.cbegin(), mLayers.cend(),
395                        [](const Layer& layer) { return layer.getState()->isProtected(); });
396 }
397 
hasSolidColorLayers() const398 bool CachedSet::hasSolidColorLayers() const {
399     return std::any_of(mLayers.cbegin(), mLayers.cend(), [](const Layer& layer) {
400         return layer.getState()->hasSolidColorCompositionType();
401     });
402 }
403 
cachingHintExcludesLayers() const404 bool CachedSet::cachingHintExcludesLayers() const {
405     const bool shouldExcludeLayers =
406             std::any_of(mLayers.cbegin(), mLayers.cend(), [](const Layer& layer) {
407                 return layer.getState()->getCachingHint() == gui::CachingHint::Disabled;
408             });
409 
410     LOG_ALWAYS_FATAL_IF(shouldExcludeLayers && getLayerCount() > 1,
411                         "CachedSet is invalid: should be excluded but contains %zu layers",
412                         getLayerCount());
413     return shouldExcludeLayers;
414 }
415 
dump(std::string & result) const416 void CachedSet::dump(std::string& result) const {
417     const auto now = std::chrono::steady_clock::now();
418 
419     const auto lastUpdate =
420             std::chrono::duration_cast<std::chrono::milliseconds>(now - mLastUpdate);
421     base::StringAppendF(&result, "  + Fingerprint %016zx, last update %sago, age %zd\n",
422                         mFingerprint, durationString(lastUpdate).c_str(), mAge);
423     {
424         const auto b = mTexture ? mTexture->get()->getBuffer().get() : nullptr;
425         base::StringAppendF(&result, "    Override buffer: %p\n", b);
426     }
427     base::StringAppendF(&result, "    HolePunchLayer: %p\t%s\n", mHolePunchLayer,
428                         mHolePunchLayer
429                                 ? mHolePunchLayer->getOutputLayer()->getLayerFE().getDebugName()
430                                 : "");
431 
432     if (mLayers.size() == 1) {
433         base::StringAppendF(&result, "    Layer [%s]\n", mLayers[0].getName().c_str());
434         if (const sp<GraphicBuffer> buffer = mLayers[0].getState()->getBuffer().promote()) {
435             base::StringAppendF(&result, "    Buffer %p", buffer.get());
436             base::StringAppendF(&result, "    Format %s",
437                                 decodePixelFormat(buffer->getPixelFormat()).c_str());
438         }
439         base::StringAppendF(&result, "    Protected [%s]\n",
440                             mLayers[0].getState()->isProtected() ? "true" : "false");
441     } else {
442         result.append("    Cached set of:\n");
443         for (const Layer& layer : mLayers) {
444             base::StringAppendF(&result, "      Layer [%s]\n", layer.getName().c_str());
445             if (const sp<GraphicBuffer> buffer = layer.getState()->getBuffer().promote()) {
446                 base::StringAppendF(&result, "       Buffer %p", buffer.get());
447                 base::StringAppendF(&result, "    Format[%s]",
448                                     decodePixelFormat(buffer->getPixelFormat()).c_str());
449             }
450             base::StringAppendF(&result, "       Protected [%s]\n",
451                                 layer.getState()->isProtected() ? "true" : "false");
452         }
453     }
454 
455     base::StringAppendF(&result, "    Creation cost: %zd\n", getCreationCost());
456     base::StringAppendF(&result, "    Display cost: %zd\n", getDisplayCost());
457 }
458 
459 } // namespace android::compositionengine::impl::planner
460