SF: Bundle ftl::Flags for CompositionCoverage
...as they will later be passed to Scheduler via ICompositor. For now,
extract ICompositor to its own header, alongside CompositionCoverage.
Bug: 241285475
Bug: 241285191
Test: Frame misses are still traced.
Change-Id: I1562893c9357a02aa42516e775700065b9b17e4b
diff --git a/services/surfaceflinger/Scheduler/MessageQueue.cpp b/services/surfaceflinger/Scheduler/MessageQueue.cpp
index 9b04497..dec8f59 100644
--- a/services/surfaceflinger/Scheduler/MessageQueue.cpp
+++ b/services/surfaceflinger/Scheduler/MessageQueue.cpp
@@ -17,12 +17,12 @@
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
#include <binder/IPCThreadState.h>
-
+#include <gui/DisplayEventReceiver.h>
#include <utils/Log.h>
#include <utils/Timers.h>
#include <utils/threads.h>
-#include <gui/DisplayEventReceiver.h>
+#include <scheduler/interface/ICompositor.h>
#include "EventThread.h"
#include "FrameTimeline.h"
diff --git a/services/surfaceflinger/Scheduler/MessageQueue.h b/services/surfaceflinger/Scheduler/MessageQueue.h
index ad0ea72..0d59337 100644
--- a/services/surfaceflinger/Scheduler/MessageQueue.h
+++ b/services/surfaceflinger/Scheduler/MessageQueue.h
@@ -37,15 +37,7 @@
namespace android {
-struct ICompositor {
- virtual void configure() = 0;
- virtual bool commit(TimePoint frameTime, VsyncId, TimePoint expectedVsyncTime) = 0;
- virtual void composite(TimePoint frameTime, VsyncId) = 0;
- virtual void sample() = 0;
-
-protected:
- ~ICompositor() = default;
-};
+struct ICompositor;
template <typename F>
class Task : public MessageHandler {
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 1fc1519..1e97f35 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -34,6 +34,8 @@
#include <utils/Trace.h>
#include <FrameTimeline/FrameTimeline.h>
+#include <scheduler/interface/ICompositor.h>
+
#include <algorithm>
#include <cinttypes>
#include <cstdint>
diff --git a/services/surfaceflinger/Scheduler/include/scheduler/interface/CompositionCoverage.h b/services/surfaceflinger/Scheduler/include/scheduler/interface/CompositionCoverage.h
new file mode 100644
index 0000000..3d0f1a9
--- /dev/null
+++ b/services/surfaceflinger/Scheduler/include/scheduler/interface/CompositionCoverage.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <cstdint>
+
+#include <ftl/flags.h>
+
+namespace android {
+
+// Whether composition was covered by HWC and/or GPU.
+enum class CompositionCoverage : std::uint8_t {
+ Hwc = 1 << 0,
+
+ // Mutually exclusive: The composition either used the GPU, or reused a buffer that had been
+ // composited on the GPU.
+ Gpu = 1 << 1,
+ GpuReuse = 1 << 2,
+};
+
+using CompositionCoverageFlags = ftl::Flags<CompositionCoverage>;
+
+} // namespace android
diff --git a/services/surfaceflinger/Scheduler/include/scheduler/interface/ICompositor.h b/services/surfaceflinger/Scheduler/include/scheduler/interface/ICompositor.h
new file mode 100644
index 0000000..cc41925
--- /dev/null
+++ b/services/surfaceflinger/Scheduler/include/scheduler/interface/ICompositor.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <scheduler/Time.h>
+#include <scheduler/VsyncId.h>
+
+namespace android {
+
+struct ICompositor {
+ // Configures physical displays, processing hotplug and/or mode setting via the Composer HAL.
+ virtual void configure() = 0;
+
+ // Commits transactions for layers and displays. Returns whether any state has been invalidated,
+ // i.e. whether a frame should be composited for each display.
+ virtual bool commit(TimePoint frameTime, VsyncId, TimePoint expectedVsyncTime) = 0;
+
+ // Composites a frame for each display. CompositionEngine performs GPU and/or HAL composition
+ // via RenderEngine and the Composer HAL, respectively.
+ virtual void composite(TimePoint frameTime, VsyncId) = 0;
+
+ // Samples the composited frame via RegionSamplingThread.
+ virtual void sample() = 0;
+
+protected:
+ ~ICompositor() = default;
+};
+
+} // namespace android
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 7d0dc93..0dc8b05 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -408,15 +408,8 @@
mDebugFlashDelay = base::GetUintProperty("debug.sf.showupdates"s, 0u);
- // DDMS debugging deprecated (b/120782499)
- property_get("debug.sf.ddms", value, "0");
- int debugDdms = atoi(value);
- ALOGI_IF(debugDdms, "DDMS debugging not supported");
-
- property_get("debug.sf.enable_gl_backpressure", value, "1");
- mPropagateBackpressureClientComposition = atoi(value);
- ALOGI_IF(mPropagateBackpressureClientComposition,
- "Enabling backpressure propagation for Client Composition");
+ mBackpressureGpuComposition = base::GetBoolProperty("debug.sf.enable_gl_backpressure"s, true);
+ ALOGI_IF(mBackpressureGpuComposition, "Enabling backpressure for GPU composition");
property_get("ro.surface_flinger.supports_background_blur", value, "0");
bool supportsBlurs = atoi(value);
@@ -2155,11 +2148,11 @@
const Period vsyncPeriod = mScheduler->getVsyncSchedule().period();
const FenceTimePtr& previousPresentFence = getPreviousPresentFence(frameTime, vsyncPeriod);
- // When Backpressure propagation is enabled we want to give a small grace period
+ // When backpressure propagation is enabled, we want to give a small grace period of 1ms
// for the present fence to fire instead of just giving up on this frame to handle cases
// where present fence is just about to get signaled.
- const int graceTimeForPresentFenceMs =
- (mPropagateBackpressureClientComposition || !mHadClientComposition) ? 1 : 0;
+ const int graceTimeForPresentFenceMs = static_cast<int>(
+ mBackpressureGpuComposition || !mCompositionCoverage.test(CompositionCoverage::Gpu));
// Pending frames may trigger backpressure propagation.
const TracedOrdinal<bool> framePending = {"PrevFramePending",
@@ -2182,9 +2175,14 @@
(lastScheduledPresentTime.ns() <
previousPresentTime - frameMissedSlop))};
const TracedOrdinal<bool> hwcFrameMissed = {"PrevHwcFrameMissed",
- mHadDeviceComposition && frameMissed};
+ frameMissed &&
+ mCompositionCoverage.test(
+ CompositionCoverage::Hwc)};
+
const TracedOrdinal<bool> gpuFrameMissed = {"PrevGpuFrameMissed",
- mHadClientComposition && frameMissed};
+ frameMissed &&
+ mCompositionCoverage.test(
+ CompositionCoverage::Gpu)};
if (frameMissed) {
mFrameMissedCount++;
@@ -2222,7 +2220,7 @@
}
if (framePending) {
- if ((hwcFrameMissed && !gpuFrameMissed) || mPropagateBackpressureClientComposition) {
+ if (mBackpressureGpuComposition || (hwcFrameMissed && !gpuFrameMissed)) {
scheduleCommit(FrameHint::kNone);
return false;
}
@@ -2459,29 +2457,43 @@
postComposition(presentTime);
- const bool prevFrameHadClientComposition = mHadClientComposition;
+ const bool hadGpuComposited = mCompositionCoverage.test(CompositionCoverage::Gpu);
+ mCompositionCoverage.clear();
- mHadClientComposition = mHadDeviceComposition = mReusedClientComposition = false;
TimeStats::ClientCompositionRecord clientCompositionRecord;
for (const auto& [_, display] : displays) {
const auto& state = display->getCompositionDisplay()->getState();
- mHadClientComposition |= state.usesClientComposition && !state.reusedClientComposition;
- mHadDeviceComposition |= state.usesDeviceComposition;
- mReusedClientComposition |= state.reusedClientComposition;
+
+ if (state.usesDeviceComposition) {
+ mCompositionCoverage |= CompositionCoverage::Hwc;
+ }
+
+ if (state.reusedClientComposition) {
+ mCompositionCoverage |= CompositionCoverage::GpuReuse;
+ } else if (state.usesClientComposition) {
+ mCompositionCoverage |= CompositionCoverage::Gpu;
+ }
+
clientCompositionRecord.predicted |=
(state.strategyPrediction != CompositionStrategyPredictionState::DISABLED);
clientCompositionRecord.predictionSucceeded |=
(state.strategyPrediction == CompositionStrategyPredictionState::SUCCESS);
}
- clientCompositionRecord.hadClientComposition = mHadClientComposition;
- clientCompositionRecord.reused = mReusedClientComposition;
- clientCompositionRecord.changed = prevFrameHadClientComposition != mHadClientComposition;
+ const bool hasGpuComposited = mCompositionCoverage.test(CompositionCoverage::Gpu);
+
+ clientCompositionRecord.hadClientComposition = hasGpuComposited;
+ clientCompositionRecord.reused = mCompositionCoverage.test(CompositionCoverage::GpuReuse);
+ clientCompositionRecord.changed = hadGpuComposited != hasGpuComposited;
+
mTimeStats->pushCompositionStrategyState(clientCompositionRecord);
- // TODO: b/160583065 Enable skip validation when SF caches all client composition layers
- const bool usedGpuComposition = mHadClientComposition || mReusedClientComposition;
- mScheduler->modulateVsync(&VsyncModulator::onDisplayRefresh, usedGpuComposition);
+ using namespace ftl::flag_operators;
+
+ // TODO(b/160583065): Enable skip validation when SF caches all client composition layers.
+ const bool hasGpuUseOrReuse =
+ mCompositionCoverage.any(CompositionCoverage::Gpu | CompositionCoverage::GpuReuse);
+ mScheduler->modulateVsync(&VsyncModulator::onDisplayRefresh, hasGpuUseOrReuse);
mLayersWithQueuedFrames.clear();
if (mLayerTracingEnabled && mLayerTracing.flagIsSet(LayerTracing::TRACE_COMPOSITION)) {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 207dfe2..ed09c3f 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -57,6 +57,8 @@
#include <scheduler/PresentLatencyTracker.h>
#include <scheduler/Time.h>
#include <scheduler/TransactionSchedule.h>
+#include <scheduler/interface/CompositionCoverage.h>
+#include <scheduler/interface/ICompositor.h>
#include <ui/FenceResult.h>
#include "Display/DisplayMap.h"
@@ -606,19 +608,9 @@
void onComposerHalVsyncIdle(hal::HWDisplayId) override;
// ICompositor overrides:
-
- // Configures physical displays, processing hotplug and/or mode setting via the Composer HAL.
void configure() override;
-
- // Commits transactions for layers and displays. Returns whether any state has been invalidated,
- // i.e. whether a frame should be composited for each display.
bool commit(TimePoint frameTime, VsyncId, TimePoint expectedVsyncTime) override;
-
- // Composites a frame for each display. CompositionEngine performs GPU and/or HAL composition
- // via RenderEngine and the Composer HAL, respectively.
void composite(TimePoint frameTime, VsyncId) override;
-
- // Samples the composited frame via RegionSamplingThread.
void sample() override;
// ISchedulerCallback overrides:
@@ -1158,17 +1150,6 @@
// Tracks layers that need to update a display's dirty region.
std::vector<sp<Layer>> mLayersPendingRefresh;
- // True if in the previous frame at least one layer was composed via the GPU.
- bool mHadClientComposition = false;
- // True if in the previous frame at least one layer was composed via HW Composer.
- // Note that it is possible for a frame to be composed via both client and device
- // composition, for example in the case of overlays.
- bool mHadDeviceComposition = false;
- // True if in the previous frame, the client composition was skipped by reusing the buffer
- // used in a previous composition. This can happed if the client composition requests
- // did not change.
- bool mReusedClientComposition = false;
-
BootStage mBootStage = BootStage::BOOTLOADER;
struct HotplugEvent {
@@ -1204,7 +1185,7 @@
std::atomic_bool mForceFullDamage = false;
bool mLayerCachingEnabled = false;
- bool mPropagateBackpressureClientComposition = false;
+ bool mBackpressureGpuComposition = false;
LayerTracing mLayerTracing{*this};
bool mLayerTracingEnabled = false;
@@ -1268,6 +1249,9 @@
std::atomic<int> mNumTrustedPresentationListeners = 0;
std::unique_ptr<compositionengine::CompositionEngine> mCompositionEngine;
+
+ CompositionCoverageFlags mCompositionCoverage;
+
// mMaxRenderTargetSize is only set once in init() so it doesn't need to be protected by
// any mutex.
size_t mMaxRenderTargetSize{1};
diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h
index 0cbfa63..74885d8 100644
--- a/services/surfaceflinger/tests/unittests/TestableScheduler.h
+++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h
@@ -16,11 +16,12 @@
#pragma once
-#include <Scheduler/Scheduler.h>
#include <ftl/fake_guard.h>
#include <gmock/gmock.h>
#include <gui/ISurfaceComposer.h>
+#include <scheduler/interface/ICompositor.h>
+
#include "Scheduler/EventThread.h"
#include "Scheduler/LayerHistory.h"
#include "Scheduler/Scheduler.h"