Support toggling layer caching at runtime
The use-case for this is dynamically enabling and disabling layer
caching when a bad layer state is encountered that is difficult to
reproduce.
Bug: 187448777
Test: adb shell service call SurfaceFlinger 1040 i32 1
Test: libcompositionengine_test
Change-Id: Id441a0894ff5a4c654db9fd706ceb1c0d1c343f0
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
index 4976213..9fba7aa 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
@@ -163,6 +163,9 @@
// Enables (or disables) composition on this output
virtual void setCompositionEnabled(bool) = 0;
+ // Enables (or disables) layer caching on this output
+ virtual void setLayerCachingEnabled(bool) = 0;
+
// Sets the projection state to use
virtual void setProjection(ui::Rotation orientation, const Rect& layerStackSpaceRect,
const Rect& orientedDisplaySpaceRect) = 0;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
index eeb20fc..2893c3f 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
@@ -20,6 +20,7 @@
#include <compositionengine/Output.h>
#include <compositionengine/impl/ClientCompositionRequestCache.h>
#include <compositionengine/impl/OutputCompositionState.h>
+#include <compositionengine/impl/planner/Planner.h>
#include <renderengine/DisplaySettings.h>
#include <renderengine/LayerSettings.h>
#include <memory>
@@ -28,21 +29,18 @@
namespace android::compositionengine::impl {
-namespace planner {
-class Planner;
-} // namespace planner
-
// The implementation class contains the common implementation, but does not
// actually contain the final output state.
class Output : public virtual compositionengine::Output {
public:
- Output();
+ Output() = default;
~Output() override;
// compositionengine::Output overrides
bool isValid() const override;
std::optional<DisplayId> getDisplayId() const override;
void setCompositionEnabled(bool) override;
+ void setLayerCachingEnabled(bool) override;
void setProjection(ui::Rotation orientation, const Rect& layerStackSpaceRect,
const Rect& orientedDisplaySpaceRect) override;
void setDisplaySize(const ui::Size&) override;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
index 5aa53e5..749675d 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
@@ -36,6 +36,7 @@
MOCK_CONST_METHOD0(getDisplayId, std::optional<DisplayId>());
MOCK_METHOD1(setCompositionEnabled, void(bool));
+ MOCK_METHOD1(setLayerCachingEnabled, void(bool));
MOCK_METHOD3(setProjection, void(ui::Rotation, const Rect&, const Rect&));
MOCK_METHOD1(setDisplaySize, void(const ui::Size&));
MOCK_METHOD2(setLayerStackFilter, void(uint32_t, bool));
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 297e687..796fe7d 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -55,18 +55,6 @@
namespace impl {
-Output::Output() {
- const bool enableLayerCaching = [] {
- const bool enable =
- android::sysprop::SurfaceFlingerProperties::enable_layer_caching().value_or(false);
- return base::GetBoolProperty(std::string("debug.sf.enable_layer_caching"), enable);
- }();
-
- if (enableLayerCaching) {
- mPlanner = std::make_unique<planner::Planner>();
- }
-}
-
namespace {
template <typename T>
@@ -135,6 +123,21 @@
dirtyEntireOutput();
}
+void Output::setLayerCachingEnabled(bool enabled) {
+ if (enabled == (mPlanner != nullptr)) {
+ return;
+ }
+
+ if (enabled) {
+ mPlanner = std::make_unique<planner::Planner>();
+ if (mRenderSurface) {
+ mPlanner->setDisplaySize(mRenderSurface->getSize());
+ }
+ } else {
+ mPlanner.reset();
+ }
+}
+
void Output::setProjection(ui::Rotation orientation, const Rect& layerStackSpaceRect,
const Rect& orientedDisplaySpaceRect) {
auto& outputState = editState();
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index 27980a0..11736d1 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -238,6 +238,28 @@
}
/*
+ * Output::setLayerCachingEnabled()
+ */
+
+TEST_F(OutputTest, setLayerCachingEnabled_enablesCaching) {
+ const auto kSize = ui::Size(1, 1);
+ EXPECT_CALL(*mRenderSurface, getSize()).WillRepeatedly(ReturnRef(kSize));
+ mOutput->setLayerCachingEnabled(false);
+ mOutput->setLayerCachingEnabled(true);
+
+ EXPECT_TRUE(mOutput->plannerEnabled());
+}
+
+TEST_F(OutputTest, setLayerCachingEnabled_disablesCaching) {
+ const auto kSize = ui::Size(1, 1);
+ EXPECT_CALL(*mRenderSurface, getSize()).WillRepeatedly(ReturnRef(kSize));
+ mOutput->setLayerCachingEnabled(true);
+ mOutput->setLayerCachingEnabled(false);
+
+ EXPECT_FALSE(mOutput->plannerEnabled());
+}
+
+/*
* Output::setProjection()
*/
@@ -972,9 +994,7 @@
mOutput.editState().usesDeviceComposition = true;
EXPECT_CALL(mOutput, chooseCompositionStrategy()).Times(1);
- if (mOutput.plannerEnabled()) {
- EXPECT_CALL(mOutput, getOutputLayerCount()).WillOnce(Return(0u));
- }
+ EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(0u));
EXPECT_CALL(*mRenderSurface, prepareFrame(false, true));
mOutput.prepareFrame();
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index d8a7514..3397011 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -139,6 +139,10 @@
getCompositionDisplay()->setCompositionEnabled(mPowerMode != hal::PowerMode::OFF);
}
+void DisplayDevice::enableLayerCaching(bool enable) {
+ getCompositionDisplay()->setLayerCachingEnabled(enable);
+}
+
hal::PowerMode DisplayDevice::getPowerMode() const {
return mPowerMode;
}
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 68846d3..bf249cd 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -157,6 +157,9 @@
void setPowerMode(hardware::graphics::composer::hal::PowerMode mode);
bool isPoweredOn() const;
+ // Enables layer caching on this DisplayDevice
+ void enableLayerCaching(bool enable);
+
ui::Dataspace getCompositionDataSpace() const;
/* ------------------------------------------------------------------------
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 5bd43e1..1e39d05 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -381,6 +381,12 @@
mColorSpaceAgnosticDataspace =
static_cast<ui::Dataspace>(color_space_agnostic_dataspace(Dataspace::UNKNOWN));
+ mLayerCachingEnabled = [] {
+ const bool enable =
+ android::sysprop::SurfaceFlingerProperties::enable_layer_caching().value_or(false);
+ return base::GetBoolProperty(std::string("debug.sf.enable_layer_caching"), enable);
+ }();
+
useContextPriority = use_context_priority(true);
using Values = SurfaceFlingerProperties::primary_display_orientation_values;
@@ -2641,6 +2647,7 @@
builder.setGpuVirtualDisplayIdGenerator(mGpuVirtualDisplayIdGenerator);
builder.setName(state.displayName);
const auto compositionDisplay = getCompositionEngine().createDisplay(builder.build());
+ compositionDisplay->setLayerCachingEnabled(mLayerCachingEnabled);
sp<compositionengine::DisplaySurface> displaySurface;
sp<IGraphicBufferProducer> producer;
@@ -5186,9 +5193,9 @@
code == IBinder::SYSPROPS_TRANSACTION) {
return OK;
}
- // Numbers from 1000 to 1038 are currently used for backdoors. The code
+ // Numbers from 1000 to 1040 are currently used for backdoors. The code
// in onTransact verifies that the user is root, and has access to use SF.
- if (code >= 1000 && code <= 1039) {
+ if (code >= 1000 && code <= 1040) {
ALOGV("Accessing SurfaceFlinger through backdoor code: %u", code);
return OK;
}
@@ -5572,6 +5579,33 @@
mScheduler->onFrameRateOverridesChanged(mAppConnectionHandle, displayId);
return NO_ERROR;
}
+ // Toggle caching feature
+ // First argument is an int32 - nonzero enables caching and zero disables caching
+ // Second argument is an optional uint64 - if present, then limits enabling/disabling
+ // caching to a particular physical display
+ case 1040: {
+ n = data.readInt32();
+ std::optional<PhysicalDisplayId> inputId = std::nullopt;
+ if (uint64_t inputDisplayId; data.readUint64(&inputDisplayId) == NO_ERROR) {
+ inputId = DisplayId::fromValue<PhysicalDisplayId>(inputDisplayId);
+ if (!inputId || getPhysicalDisplayToken(*inputId)) {
+ ALOGE("No display with id: %" PRIu64, inputDisplayId);
+ return NAME_NOT_FOUND;
+ }
+ }
+ {
+ Mutex::Autolock lock(mStateLock);
+ mLayerCachingEnabled = n != 0;
+ for (const auto& [_, display] : mDisplays) {
+ if (!inputId || *inputId == display->getPhysicalId()) {
+ display->enableLayerCaching(mLayerCachingEnabled);
+ }
+ }
+ }
+ invalidateHwcGeometry();
+ repaintEverything();
+ return NO_ERROR;
+ }
}
}
return err;
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 0a6a8e7..4009baf 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -1244,6 +1244,7 @@
int mDebugRegion = 0;
bool mDebugDisableHWC = false;
bool mDebugDisableTransformHint = false;
+ bool mLayerCachingEnabled = false;
volatile nsecs_t mDebugInTransaction = 0;
bool mForceFullDamage = false;
bool mPropagateBackpressureClientComposition = false;