diff options
15 files changed, 172 insertions, 40 deletions
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h index 31d6365bf4..298aff57a9 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h @@ -58,6 +58,9 @@ public: 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 2a901ae68b..db4f9698e2 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h @@ -43,6 +43,10 @@ public: // 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 d5763d5611..6a0caf0746 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h @@ -122,6 +122,13 @@ struct LayerFECompositionState { // 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 5f62b32c9a..cedd728588 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h @@ -78,12 +78,18 @@ public: // 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 96e609d1c9..982a37604d 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h @@ -39,6 +39,8 @@ public: 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 4c3f9359b0..fa4d8cd6db 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h @@ -49,9 +49,11 @@ public: 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 82ecec502d..6450b222dc 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h @@ -44,6 +44,7 @@ public: 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 48c2dbf3d6..e2802954d6 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h @@ -33,6 +33,7 @@ public: 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 d8d637d302..6b2224ac60 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h @@ -40,9 +40,11 @@ public: 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 9558266a34..8bc3a349ca 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 @@ nsecs_t CompositionEngine::getLastFrameRefreshTimestamp() const { 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 e721cf5375..73bb03be02 100644 --- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp +++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp @@ -550,6 +550,27 @@ void OutputLayer::writeCompositionTypeToHWC( } } +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 @@ bool OutputLayer::requiresClientComposition() const { 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 c83cae65fb..75e960c575 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp @@ -782,6 +782,61 @@ TEST_F(OutputLayerWriteStateToHWCTest, compositionTypeIsSetToClientIfClientCompo } /* + * 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 @@ TEST_F(OutputLayerTest, requiresClientCompositionReturnsFalseIfSetToDeviceCompos } /* + * 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 5121835cae..557d0bba27 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -464,6 +464,21 @@ void Layer::latchPerFrameState(compositionengine::LayerFECompositionState& compo } } +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 @@ const char* Layer::getDebugName() const { 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 aa3970eb3a..23763d2729 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -476,6 +476,7 @@ public: 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 @@ public: 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 83f3b2cecd..8760bb0900 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2715,15 +2715,14 @@ void SurfaceFlinger::executeInputWindowCommands() { 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() |