Prevent HDRLayerInfoListener traversal from running on every frame
We should only have to update the HDRLayerInfoListener in a few
scenarios.
1. A new listener appeared
2. A buffer changed colorspace
3. Surface geometry (visibility, parenting, display, etc) changed
We protect the traversal behind these flags to avoid the runtime in the
hot path of continuous buffer updates. A follow up fix could consider
directly recursively traversing and early returning if !Layer->isVisible.
Bug: 186200583
Test: Existing tests pass, simpleperf
Change-Id: I549fdf6ea228344f79f6989b86b8e73a6065158a
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 7270016..76221bc 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1643,6 +1643,9 @@
hdrInfoReporter = sp<HdrLayerInfoReporter>::make();
}
hdrInfoReporter->addListener(listener);
+
+
+ mAddingHDRLayerInfoListener = true;
return OK;
}
@@ -2143,6 +2146,8 @@
mTracing.notify("bufferLatched");
}
}
+
+ mVisibleRegionsWereDirtyThisFrame = mVisibleRegionsDirty; // Cache value for use in post-comp
mVisibleRegionsDirty = false;
if (mCompositionEngine->needsAnotherUpdate()) {
@@ -2287,6 +2292,7 @@
std::vector<std::pair<std::shared_ptr<compositionengine::Display>, sp<HdrLayerInfoReporter>>>
hdrInfoListeners;
+ bool haveNewListeners = false;
{
Mutex::Autolock lock(mStateLock);
if (mFpsReporter) {
@@ -2304,37 +2310,45 @@
}
}
}
+ haveNewListeners = mAddingHDRLayerInfoListener; // grab this with state lock
+ mAddingHDRLayerInfoListener = false;
}
- for (auto& [compositionDisplay, listener] : hdrInfoListeners) {
- HdrLayerInfoReporter::HdrLayerInfo info;
- int32_t maxArea = 0;
- mDrawingState.traverse([&, compositionDisplay = compositionDisplay](Layer* layer) {
- const auto layerFe = layer->getCompositionEngineLayerFE();
- if (layer->isVisible() && compositionDisplay->belongsInOutput(layerFe)) {
- const Dataspace transfer =
+ if (haveNewListeners || mSomeDataspaceChanged || mVisibleRegionsWereDirtyThisFrame) {
+ for (auto& [compositionDisplay, listener] : hdrInfoListeners) {
+ HdrLayerInfoReporter::HdrLayerInfo info;
+ int32_t maxArea = 0;
+ mDrawingState.traverse([&, compositionDisplay = compositionDisplay](Layer* layer) {
+ const auto layerFe = layer->getCompositionEngineLayerFE();
+ if (layer->isVisible() && compositionDisplay->belongsInOutput(layerFe)) {
+ const Dataspace transfer =
static_cast<Dataspace>(layer->getDataSpace() & Dataspace::TRANSFER_MASK);
- const bool isHdr = (transfer == Dataspace::TRANSFER_ST2084 ||
- transfer == Dataspace::TRANSFER_HLG);
+ const bool isHdr = (transfer == Dataspace::TRANSFER_ST2084 ||
+ transfer == Dataspace::TRANSFER_HLG);
- if (isHdr) {
- const auto* outputLayer = compositionDisplay->getOutputLayerForLayer(layerFe);
- if (outputLayer) {
- info.numberOfHdrLayers++;
- const auto displayFrame = outputLayer->getState().displayFrame;
- const int32_t area = displayFrame.width() * displayFrame.height();
- if (area > maxArea) {
- maxArea = area;
- info.maxW = displayFrame.width();
- info.maxH = displayFrame.height();
+ if (isHdr) {
+ const auto* outputLayer =
+ compositionDisplay->getOutputLayerForLayer(layerFe);
+ if (outputLayer) {
+ info.numberOfHdrLayers++;
+ const auto displayFrame = outputLayer->getState().displayFrame;
+ const int32_t area = displayFrame.width() * displayFrame.height();
+ if (area > maxArea) {
+ maxArea = area;
+ info.maxW = displayFrame.width();
+ info.maxH = displayFrame.height();
+ }
}
}
}
- }
- });
- listener->dispatchHdrLayerInfo(info);
+ });
+ listener->dispatchHdrLayerInfo(info);
+ }
}
+ mSomeDataspaceChanged = false;
+ mVisibleRegionsWereDirtyThisFrame = false;
+
mTransactionCallbackInvoker.addPresentFence(mPreviousPresentFences[0].fence);
mTransactionCallbackInvoker.sendCallbacks();