SF: Move/Refactor updateCursorAsync to CompositionEngine
As part of this change, the existing LayerFE::latchCompositionState is
extended to allow for more state types to be fetched.
Test: atest libsurfaceflinger_unittest libcompositionengine_test
Bug: 121291683
Change-Id: I71e0f547440a64c1025f36741beb68e72c18e475
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h
index 31d6365..298aff5 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h
@@ -58,6 +58,9 @@
virtual bool needsAnotherUpdate() const = 0;
virtual nsecs_t getLastFrameRefreshTimestamp() const = 0;
+ // Updates the cursor position for the indicated outputs.
+ virtual void updateCursorAsync(CompositionRefreshArgs&) = 0;
+
// TODO(b/121291683): These will become private/internal
virtual void preComposition(CompositionRefreshArgs&) = 0;
};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
index 2a901ae..db4f969 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
@@ -43,6 +43,10 @@
// geometry state can be skipped.
virtual void latchCompositionState(LayerFECompositionState&, bool includeGeometry) const = 0;
+ // Latches the minimal bit of state for the cursor for a fast asynchronous
+ // update.
+ virtual void latchCursorCompositionState(LayerFECompositionState&) const = 0;
+
struct ClientCompositionTargetSettings {
// The clip region, or visible region that is being rendered to
const Region& clip;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
index d5763d5..6a0caf0 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
@@ -122,6 +122,13 @@
// True if the layer has protected content
bool hasProtectedContent{false};
+
+ /*
+ * Cursor state
+ */
+
+ // The output-independent frame for the cursor
+ Rect cursorFrame;
};
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
index 5f62b32c..cedd728 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
@@ -78,12 +78,18 @@
// skipped.
virtual void writeStateToHWC(bool includeGeometry) = 0;
+ // Updates the cursor position with the HWC
+ virtual void writeCursorPositionToHWC() const = 0;
+
// Returns the HWC2::Layer associated with this layer, if it exists
virtual HWC2::Layer* getHwcLayer() const = 0;
// Returns true if the current layer state requires client composition
virtual bool requiresClientComposition() const = 0;
+ // Returns true if the current layer should be treated as a cursor layer
+ virtual bool isHardwareCursor() const = 0;
+
// Applies a HWC device requested composition type change
virtual void applyDeviceCompositionTypeChange(Hwc2::IComposerClient::Composition) = 0;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h
index 96e609d..982a376 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h
@@ -39,6 +39,8 @@
bool needsAnotherUpdate() const override;
nsecs_t getLastFrameRefreshTimestamp() const override;
+ void updateCursorAsync(CompositionRefreshArgs&) override;
+
void preComposition(CompositionRefreshArgs&) override;
// Testing
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
index 4c3f935..fa4d8cd 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
@@ -49,9 +49,11 @@
void updateCompositionState(bool) override;
void writeStateToHWC(bool) override;
+ void writeCursorPositionToHWC() const override;
HWC2::Layer* getHwcLayer() const override;
bool requiresClientComposition() const override;
+ bool isHardwareCursor() const override;
void applyDeviceCompositionTypeChange(Hwc2::IComposerClient::Composition) override;
void prepareForDeviceLayerRequests() override;
void applyDeviceLayerRequest(Hwc2::IComposerClient::LayerRequest request) override;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h
index 82ecec5..6450b22 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h
@@ -44,6 +44,7 @@
MOCK_CONST_METHOD0(needsAnotherUpdate, bool());
MOCK_CONST_METHOD0(getLastFrameRefreshTimestamp, nsecs_t());
+ MOCK_METHOD1(updateCursorAsync, void(CompositionRefreshArgs&));
MOCK_METHOD1(preComposition, void(CompositionRefreshArgs&));
};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
index 48c2dbf..e280295 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
@@ -33,6 +33,7 @@
MOCK_METHOD1(onPreComposition, bool(nsecs_t));
MOCK_CONST_METHOD2(latchCompositionState, void(LayerFECompositionState&, bool));
+ MOCK_CONST_METHOD1(latchCursorCompositionState, void(LayerFECompositionState&));
MOCK_METHOD1(prepareClientComposition,
std::optional<renderengine::LayerSettings>(
compositionengine::LayerFE::ClientCompositionTargetSettings&));
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
index d8d637d..6b2224a 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
@@ -40,9 +40,11 @@
MOCK_METHOD1(updateCompositionState, void(bool));
MOCK_METHOD1(writeStateToHWC, void(bool));
+ MOCK_CONST_METHOD0(writeCursorPositionToHWC, void());
MOCK_CONST_METHOD0(getHwcLayer, HWC2::Layer*());
MOCK_CONST_METHOD0(requiresClientComposition, bool());
+ MOCK_CONST_METHOD0(isHardwareCursor, bool());
MOCK_METHOD1(applyDeviceCompositionTypeChange, void(Hwc2::IComposerClient::Composition));
MOCK_METHOD0(prepareForDeviceLayerRequests, void());
MOCK_METHOD1(applyDeviceLayerRequest, void(Hwc2::IComposerClient::LayerRequest request));
diff --git a/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp b/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp
index 9558266..8bc3a34 100644
--- a/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp
@@ -16,6 +16,7 @@
#include <compositionengine/CompositionRefreshArgs.h>
#include <compositionengine/LayerFE.h>
+#include <compositionengine/OutputLayer.h>
#include <compositionengine/impl/CompositionEngine.h>
#include <compositionengine/impl/Display.h>
#include <compositionengine/impl/Layer.h>
@@ -70,6 +71,22 @@
return mRefreshStartTime;
}
+void CompositionEngine::updateCursorAsync(CompositionRefreshArgs& args) {
+ std::unordered_map<compositionengine::LayerFE*, compositionengine::LayerFECompositionState*>
+ uniqueVisibleLayers;
+
+ for (const auto& output : args.outputs) {
+ for (auto& layer : output->getOutputLayersOrderedByZ()) {
+ if (layer->isHardwareCursor()) {
+ // Latch the cursor composition state from each front-end layer.
+ layer->getLayerFE().latchCursorCompositionState(
+ layer->getLayer().editState().frontEnd);
+ layer->writeCursorPositionToHWC();
+ }
+ }
+ }
+}
+
void CompositionEngine::preComposition(CompositionRefreshArgs& args) {
ATRACE_CALL();
ALOGV(__FUNCTION__);
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index e721cf5..73bb03b 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -550,6 +550,27 @@
}
}
+void OutputLayer::writeCursorPositionToHWC() const {
+ // Skip doing this if there is no HWC interface
+ auto hwcLayer = getHwcLayer();
+ if (!hwcLayer) {
+ return;
+ }
+
+ const auto& layerFEState = mLayer->getState().frontEnd;
+ const auto& outputState = mOutput.getState();
+
+ Rect frame = layerFEState.cursorFrame;
+ frame.intersect(outputState.viewport, &frame);
+ Rect position = outputState.transform.transform(frame);
+
+ if (auto error = hwcLayer->setCursorPosition(position.left, position.top);
+ error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set cursor position to (%d, %d): %s (%d)", mLayerFE->getDebugName(),
+ position.left, position.top, to_string(error).c_str(), static_cast<int32_t>(error));
+ }
+}
+
HWC2::Layer* OutputLayer::getHwcLayer() const {
return mState.hwc ? mState.hwc->hwcLayer.get() : nullptr;
}
@@ -559,6 +580,11 @@
mState.hwc->hwcCompositionType == Hwc2::IComposerClient::Composition::CLIENT;
}
+bool OutputLayer::isHardwareCursor() const {
+ return mState.hwc &&
+ mState.hwc->hwcCompositionType == Hwc2::IComposerClient::Composition::CURSOR;
+}
+
void OutputLayer::detectDisallowedCompositionTypeChange(
Hwc2::IComposerClient::Composition from, Hwc2::IComposerClient::Composition to) const {
bool result = false;
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
index c83cae6..75e960c 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
@@ -782,6 +782,61 @@
}
/*
+ * OutputLayer::writeCursorPositionToHWC()
+ */
+
+struct OutputLayerWriteCursorPositionToHWCTest : public OutputLayerTest {
+ static constexpr int kDefaultTransform = TR_IDENT;
+ static constexpr HWC2::Error kDefaultError = HWC2::Error::Unsupported;
+
+ static const Rect kDefaultDisplayViewport;
+ static const Rect kDefaultCursorFrame;
+
+ OutputLayerWriteCursorPositionToHWCTest() {
+ auto& outputLayerState = mOutputLayer.editState();
+ outputLayerState.hwc = impl::OutputLayerCompositionState::Hwc(mHwcLayer);
+
+ mLayerState.frontEnd.cursorFrame = kDefaultCursorFrame;
+
+ mOutputState.viewport = kDefaultDisplayViewport;
+ mOutputState.transform = ui::Transform{kDefaultTransform};
+ }
+
+ std::shared_ptr<HWC2::mock::Layer> mHwcLayer{std::make_shared<StrictMock<HWC2::mock::Layer>>()};
+};
+
+const Rect OutputLayerWriteCursorPositionToHWCTest::kDefaultDisplayViewport{0, 0, 1920, 1080};
+const Rect OutputLayerWriteCursorPositionToHWCTest::kDefaultCursorFrame{1, 2, 3, 4};
+
+TEST_F(OutputLayerWriteCursorPositionToHWCTest, writeCursorPositionToHWCHandlesNoHwcState) {
+ mOutputLayer.editState().hwc.reset();
+
+ mOutputLayer.writeCursorPositionToHWC();
+}
+
+TEST_F(OutputLayerWriteCursorPositionToHWCTest, writeCursorPositionToHWCWritesStateToHWC) {
+ EXPECT_CALL(*mHwcLayer, setCursorPosition(1, 2)).WillOnce(Return(kDefaultError));
+
+ mOutputLayer.writeCursorPositionToHWC();
+}
+
+TEST_F(OutputLayerWriteCursorPositionToHWCTest, writeCursorPositionToHWCIntersectedWithViewport) {
+ mLayerState.frontEnd.cursorFrame = Rect{3000, 3000, 3016, 3016};
+
+ EXPECT_CALL(*mHwcLayer, setCursorPosition(1920, 1080)).WillOnce(Return(kDefaultError));
+
+ mOutputLayer.writeCursorPositionToHWC();
+}
+
+TEST_F(OutputLayerWriteCursorPositionToHWCTest, writeCursorPositionToHWCRotatedByTransform) {
+ mOutputState.transform = ui::Transform{TR_ROT_90};
+
+ EXPECT_CALL(*mHwcLayer, setCursorPosition(-4, 1)).WillOnce(Return(kDefaultError));
+
+ mOutputLayer.writeCursorPositionToHWC();
+}
+
+/*
* OutputLayer::getHwcLayer()
*/
@@ -829,6 +884,30 @@
}
/*
+ * OutputLayer::isHardwareCursor()
+ */
+
+TEST_F(OutputLayerTest, isHardwareCursorReturnsFalseIfNoHWC2State) {
+ mOutputLayer.editState().hwc.reset();
+
+ EXPECT_FALSE(mOutputLayer.isHardwareCursor());
+}
+
+TEST_F(OutputLayerTest, isHardwareCursorReturnsTrueIfSetToCursorComposition) {
+ mOutputLayer.editState().hwc = impl::OutputLayerCompositionState::Hwc{nullptr};
+ mOutputLayer.editState().hwc->hwcCompositionType = Hwc2::IComposerClient::Composition::CURSOR;
+
+ EXPECT_TRUE(mOutputLayer.isHardwareCursor());
+}
+
+TEST_F(OutputLayerTest, isHardwareCursorReturnsFalseIfSetToDeviceComposition) {
+ mOutputLayer.editState().hwc = impl::OutputLayerCompositionState::Hwc{nullptr};
+ mOutputLayer.editState().hwc->hwcCompositionType = Hwc2::IComposerClient::Composition::DEVICE;
+
+ EXPECT_FALSE(mOutputLayer.isHardwareCursor());
+}
+
+/*
* OutputLayer::applyDeviceCompositionTypeChange()
*/
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 5121835..557d0bb 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -464,6 +464,21 @@
}
}
+void Layer::latchCursorCompositionState(
+ compositionengine::LayerFECompositionState& compositionState) const {
+ // This gives us only the "orientation" component of the transform
+ const State& drawingState{getDrawingState()};
+
+ // Apply the layer's transform, followed by the display's global transform
+ // Here we're guaranteed that the layer's transform preserves rects
+ Rect win = getCroppedBufferSize(drawingState);
+ // Subtract the transparent region and snap to the bounds
+ Rect bounds = reduce(win, getActiveTransparentRegion(drawingState));
+ Rect frame(getTransform().transform(bounds));
+
+ compositionState.cursorFrame = frame;
+}
+
bool Layer::onPreComposition(nsecs_t) {
return false;
}
@@ -481,38 +496,6 @@
return mName.string();
}
-void Layer::updateCursorPosition(const sp<const DisplayDevice>& display) {
- const auto outputLayer = findOutputLayerForDisplay(display);
- LOG_FATAL_IF(!outputLayer);
-
- if (!outputLayer->getState().hwc ||
- (*outputLayer->getState().hwc).hwcCompositionType !=
- Hwc2::IComposerClient::Composition::CURSOR) {
- return;
- }
-
- // This gives us only the "orientation" component of the transform
- const State& s(getDrawingState());
-
- // Apply the layer's transform, followed by the display's global transform
- // Here we're guaranteed that the layer's transform preserves rects
- Rect win = getCroppedBufferSize(s);
- // Subtract the transparent region and snap to the bounds
- Rect bounds = reduce(win, getActiveTransparentRegion(s));
- Rect frame(getTransform().transform(bounds));
- frame.intersect(display->getViewport(), &frame);
- auto& displayTransform = display->getTransform();
- auto position = displayTransform.transform(frame);
-
- auto error =
- (*outputLayer->getState().hwc).hwcLayer->setCursorPosition(position.left, position.top);
- ALOGE_IF(error != HWC2::Error::None,
- "[%s] Failed to set cursor position "
- "to (%d, %d): %s (%d)",
- mName.string(), position.left, position.top, to_string(error).c_str(),
- static_cast<int32_t>(error));
-}
-
// ---------------------------------------------------------------------------
// drawing...
// ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index aa3970e..23763d2 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -476,6 +476,7 @@
bool onPreComposition(nsecs_t) override;
void latchCompositionState(compositionengine::LayerFECompositionState&,
bool includeGeometry) const override;
+ void latchCursorCompositionState(compositionengine::LayerFECompositionState&) const override;
std::optional<renderengine::LayerSettings> prepareClientComposition(
compositionengine::LayerFE::ClientCompositionTargetSettings&) override;
void onLayerDisplayed(const sp<Fence>& releaseFence) override;
@@ -493,7 +494,6 @@
Hwc2::IComposerClient::Composition getCompositionType(
const sp<const DisplayDevice>& display) const;
bool getClearClientTarget(const sp<const DisplayDevice>& display) const;
- void updateCursorPosition(const sp<const DisplayDevice>& display);
virtual bool shouldPresentNow(nsecs_t /*expectedPresentTime*/) const { return false; }
virtual void setTransformHint(uint32_t /*orientation*/) const { }
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 83f3b2c..8760bb0 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2715,15 +2715,14 @@
void SurfaceFlinger::updateCursorAsync()
{
- for (const auto& [token, display] : mDisplays) {
- if (!display->getId()) {
- continue;
- }
-
- for (auto& layer : display->getVisibleLayersSortedByZ()) {
- layer->updateCursorPosition(display);
+ compositionengine::CompositionRefreshArgs refreshArgs;
+ for (const auto& [_, display] : mDisplays) {
+ if (display->getId()) {
+ refreshArgs.outputs.push_back(display->getCompositionDisplay());
}
}
+
+ mCompositionEngine->updateCursorAsync(refreshArgs);
}
void SurfaceFlinger::commitTransaction()