Loading services/surfaceflinger/BufferStateLayer.cpp +2 −17 Original line number Diff line number Diff line Loading @@ -425,7 +425,8 @@ bool BufferStateLayer::setBuffer(const std::shared_ptr<renderengine::ExternalTex if (mDrawingState.buffer) { mReleasePreviousBuffer = true; if (mDrawingState.buffer != mBufferInfo.mBuffer) { if (mDrawingState.buffer != mBufferInfo.mBuffer || mDrawingState.frameNumber != mBufferInfo.mFrameNumber) { // If mDrawingState has a buffer, and we are about to update again // before swapping to drawing state, then the first buffer will be // dropped and we should decrement the pending buffer count and Loading Loading @@ -963,22 +964,6 @@ void BufferStateLayer::tracePendingBufferCount(int32_t pendingBuffers) { ATRACE_INT(mBlastTransactionName.c_str(), pendingBuffers); } void BufferStateLayer::bufferMayChange(const sp<GraphicBuffer>& newBuffer) { if (mDrawingState.buffer != nullptr && (!mBufferInfo.mBuffer || mDrawingState.buffer->getBuffer() != mBufferInfo.mBuffer->getBuffer()) && newBuffer != mDrawingState.buffer->getBuffer()) { // If we are about to update mDrawingState.buffer but it has not yet latched // then we will drop a buffer and should decrement the pending buffer count and // call any release buffer callbacks if set. callReleaseBufferCallback(mDrawingState.releaseBufferListener, mDrawingState.buffer->getBuffer(), mDrawingState.frameNumber, mDrawingState.acquireFence, mTransformHint, mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate( mOwnerUid)); decrementPendingBufferCount(); } } /* * We don't want to send the layer's transform to input, but rather the Loading services/surfaceflinger/BufferStateLayer.h +0 −1 Original line number Diff line number Diff line Loading @@ -97,7 +97,6 @@ public: // See mPendingBufferTransactions void decrementPendingBufferCount(); void bufferMayChange(const sp<GraphicBuffer>& newBuffer) override; std::atomic<int32_t>* getPendingBufferCounter() override { return &mPendingBufferTransactions; } std::string getPendingBufferCounterName() override { return mBlastTransactionName; } Loading services/surfaceflinger/Layer.cpp +60 −66 Original line number Diff line number Diff line Loading @@ -1117,46 +1117,59 @@ StretchEffect Layer::getStretchEffect() const { return StretchEffect{}; } void Layer::updateTreeHasFrameRateVote() { const auto traverseTree = [&](const LayerVector::Visitor& visitor) { auto parent = getParent(); while (parent) { visitor(parent.get()); parent = parent->getParent(); bool Layer::propagateFrameRateForLayerTree(FrameRate parentFrameRate, bool* transactionNeeded) { // The frame rate for layer tree is this layer's frame rate if present, or the parent frame rate const auto frameRate = [&] { if (mDrawingState.frameRate.rate.isValid() || mDrawingState.frameRate.type == FrameRateCompatibility::NoVote) { return mDrawingState.frameRate; } traverse(LayerVector::StateSet::Current, visitor); }; return parentFrameRate; }(); // update parents and children about the vote // First traverse the tree and count how many layers has votes. int layersWithVote = 0; traverseTree([&layersWithVote](Layer* layer) { *transactionNeeded |= setFrameRateForLayerTree(frameRate); // The frame rate is propagated to the children bool childrenHaveFrameRate = false; for (const sp<Layer>& child : mCurrentChildren) { childrenHaveFrameRate |= child->propagateFrameRateForLayerTree(frameRate, transactionNeeded); } // If we don't have a valid frame rate, but the children do, we set this // layer as NoVote to allow the children to control the refresh rate if (!frameRate.rate.isValid() && frameRate.type != FrameRateCompatibility::NoVote && childrenHaveFrameRate) { *transactionNeeded |= setFrameRateForLayerTree(FrameRate(Fps(0.0f), FrameRateCompatibility::NoVote)); } // We return whether this layer ot its children has a vote. We ignore ExactOrMultiple votes for // the same reason we are allowing touch boost for those layers. See // RefreshRateConfigs::getBestRefreshRate for more details. const auto layerVotedWithDefaultCompatibility = layer->mDrawingState.frameRate.rate.isValid() && layer->mDrawingState.frameRate.type == FrameRateCompatibility::Default; const auto layerVotedWithNoVote = layer->mDrawingState.frameRate.type == FrameRateCompatibility::NoVote; frameRate.rate.isValid() && frameRate.type == FrameRateCompatibility::Default; const auto layerVotedWithNoVote = frameRate.type == FrameRateCompatibility::NoVote; const auto layerVotedWithExactCompatibility = layer->mDrawingState.frameRate.type == FrameRateCompatibility::Exact; frameRate.rate.isValid() && frameRate.type == FrameRateCompatibility::Exact; return layerVotedWithDefaultCompatibility || layerVotedWithNoVote || layerVotedWithExactCompatibility || childrenHaveFrameRate; } // We do not count layers that are ExactOrMultiple for the same reason // we are allowing touch boost for those layers. See // RefreshRateConfigs::getBestRefreshRate for more details. if (layerVotedWithDefaultCompatibility || layerVotedWithNoVote || layerVotedWithExactCompatibility) { layersWithVote++; void Layer::updateTreeHasFrameRateVote() { const auto root = [&]() -> sp<Layer> { sp<Layer> layer = this; while (auto parent = layer->getParent()) { layer = parent; } }); return layer; }(); // Now we can update the tree frame rate vote for each layer in the tree const bool treeHasFrameRateVote = layersWithVote > 0; bool transactionNeeded = false; root->propagateFrameRateForLayerTree({}, &transactionNeeded); traverseTree([treeHasFrameRateVote, &transactionNeeded](Layer* layer) { transactionNeeded = layer->updateFrameRateForLayerTree(treeHasFrameRateVote); }); // TODO(b/195668952): we probably don't need eTraversalNeeded here if (transactionNeeded) { mFlinger->setTransactionFlags(eTraversalNeeded); } Loading Loading @@ -1283,13 +1296,15 @@ std::shared_ptr<frametimeline::SurfaceFrame> Layer::createSurfaceFrameForBuffer( return surfaceFrame; } bool Layer::updateFrameRateForLayerTree(bool treeHasFrameRateVote) { const auto updateDrawingState = [&](FrameRate frameRate) { bool Layer::setFrameRateForLayerTree(FrameRate frameRate) { if (mDrawingState.frameRateForLayerTree == frameRate) { return false; } mDrawingState.frameRateForLayerTree = frameRate; // TODO(b/195668952): we probably don't need to dirty visible regions here // or even store frameRateForLayerTree in mDrawingState mDrawingState.sequence++; mDrawingState.modified = true; setTransactionFlags(eTransactionNeeded); Loading @@ -1298,27 +1313,6 @@ bool Layer::updateFrameRateForLayerTree(bool treeHasFrameRateVote) { LayerHistory::LayerUpdateType::SetFrameRate); return true; }; const auto frameRate = mDrawingState.frameRate; if (frameRate.rate.isValid() || frameRate.type == FrameRateCompatibility::NoVote) { return updateDrawingState(frameRate); } // This layer doesn't have a frame rate. Check if its ancestors have a vote for (sp<Layer> parent = getParent(); parent; parent = parent->getParent()) { if (parent->mDrawingState.frameRate.rate.isValid()) { return updateDrawingState(parent->mDrawingState.frameRate); } } // This layer and its ancestors don't have a frame rate. If one of successors // has a vote, return a NoVote for successors to set the vote if (treeHasFrameRateVote) { return updateDrawingState(FrameRate(Fps(0.0f), FrameRateCompatibility::NoVote)); } return updateDrawingState(frameRate); } Layer::FrameRate Layer::getFrameRateForLayerTree() const { Loading services/surfaceflinger/Layer.h +2 −8 Original line number Diff line number Diff line Loading @@ -702,12 +702,6 @@ public: */ virtual uint32_t doTransaction(uint32_t transactionFlags); /* * Called before updating the drawing state buffer. Used by BufferStateLayer to release any * unlatched buffers in the drawing state. */ virtual void bufferMayChange(const sp<GraphicBuffer>& /* newBuffer */){}; /* * Remove relative z for the layer if its relative parent is not part of the * provided layer tree. Loading Loading @@ -1053,6 +1047,8 @@ private: const std::vector<Layer*>& layersInTree); void updateTreeHasFrameRateVote(); bool propagateFrameRateForLayerTree(FrameRate parentFrameRate, bool* transactionNeeded); bool setFrameRateForLayerTree(FrameRate); void setZOrderRelativeOf(const wp<Layer>& relativeOf); bool isTrustedOverlay() const; Loading @@ -1071,8 +1067,6 @@ private: // Fills in the frame and transform info for the InputWindowInfo void fillInputFrameInfo(InputWindowInfo& info, const ui::Transform& toPhysicalDisplay); bool updateFrameRateForLayerTree(bool treeHasFrameRateVote); // Cached properties computed from drawing state // Effective transform taking into account parent transforms and any parent scaling, which is // a transform from the current layer coordinate space to display(screen) coordinate space. Loading services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp +35 −0 Original line number Diff line number Diff line Loading @@ -485,5 +485,40 @@ TEST_P(SetFrameRateTest, SetOnParentActivatesTree) { EXPECT_TRUE(FRAME_RATE_VOTE1.rate.equalsWithMargin(layerHistorySummary[1].desiredRefreshRate)); } TEST_P(SetFrameRateTest, addChildForParentWithTreeVote) { EXPECT_CALL(*mMessageQueue, invalidate()).Times(1); const auto& layerFactory = GetParam(); const auto parent = mLayers.emplace_back(layerFactory->createLayer(mFlinger)); const auto child1 = mLayers.emplace_back(layerFactory->createLayer(mFlinger)); const auto child2 = mLayers.emplace_back(layerFactory->createLayer(mFlinger)); const auto childOfChild1 = mLayers.emplace_back(layerFactory->createLayer(mFlinger)); addChild(parent, child1); addChild(child1, childOfChild1); childOfChild1->setFrameRate(FRAME_RATE_VOTE1); commitTransaction(); EXPECT_EQ(FRAME_RATE_TREE, parent->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_VOTE1, childOfChild1->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree()); addChild(parent, child2); commitTransaction(); EXPECT_EQ(FRAME_RATE_TREE, parent->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_VOTE1, childOfChild1->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree()); childOfChild1->setFrameRate(FRAME_RATE_NO_VOTE); commitTransaction(); EXPECT_EQ(FRAME_RATE_NO_VOTE, parent->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_NO_VOTE, child1->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_NO_VOTE, childOfChild1->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree()); } } // namespace } // namespace android Loading
services/surfaceflinger/BufferStateLayer.cpp +2 −17 Original line number Diff line number Diff line Loading @@ -425,7 +425,8 @@ bool BufferStateLayer::setBuffer(const std::shared_ptr<renderengine::ExternalTex if (mDrawingState.buffer) { mReleasePreviousBuffer = true; if (mDrawingState.buffer != mBufferInfo.mBuffer) { if (mDrawingState.buffer != mBufferInfo.mBuffer || mDrawingState.frameNumber != mBufferInfo.mFrameNumber) { // If mDrawingState has a buffer, and we are about to update again // before swapping to drawing state, then the first buffer will be // dropped and we should decrement the pending buffer count and Loading Loading @@ -963,22 +964,6 @@ void BufferStateLayer::tracePendingBufferCount(int32_t pendingBuffers) { ATRACE_INT(mBlastTransactionName.c_str(), pendingBuffers); } void BufferStateLayer::bufferMayChange(const sp<GraphicBuffer>& newBuffer) { if (mDrawingState.buffer != nullptr && (!mBufferInfo.mBuffer || mDrawingState.buffer->getBuffer() != mBufferInfo.mBuffer->getBuffer()) && newBuffer != mDrawingState.buffer->getBuffer()) { // If we are about to update mDrawingState.buffer but it has not yet latched // then we will drop a buffer and should decrement the pending buffer count and // call any release buffer callbacks if set. callReleaseBufferCallback(mDrawingState.releaseBufferListener, mDrawingState.buffer->getBuffer(), mDrawingState.frameNumber, mDrawingState.acquireFence, mTransformHint, mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate( mOwnerUid)); decrementPendingBufferCount(); } } /* * We don't want to send the layer's transform to input, but rather the Loading
services/surfaceflinger/BufferStateLayer.h +0 −1 Original line number Diff line number Diff line Loading @@ -97,7 +97,6 @@ public: // See mPendingBufferTransactions void decrementPendingBufferCount(); void bufferMayChange(const sp<GraphicBuffer>& newBuffer) override; std::atomic<int32_t>* getPendingBufferCounter() override { return &mPendingBufferTransactions; } std::string getPendingBufferCounterName() override { return mBlastTransactionName; } Loading
services/surfaceflinger/Layer.cpp +60 −66 Original line number Diff line number Diff line Loading @@ -1117,46 +1117,59 @@ StretchEffect Layer::getStretchEffect() const { return StretchEffect{}; } void Layer::updateTreeHasFrameRateVote() { const auto traverseTree = [&](const LayerVector::Visitor& visitor) { auto parent = getParent(); while (parent) { visitor(parent.get()); parent = parent->getParent(); bool Layer::propagateFrameRateForLayerTree(FrameRate parentFrameRate, bool* transactionNeeded) { // The frame rate for layer tree is this layer's frame rate if present, or the parent frame rate const auto frameRate = [&] { if (mDrawingState.frameRate.rate.isValid() || mDrawingState.frameRate.type == FrameRateCompatibility::NoVote) { return mDrawingState.frameRate; } traverse(LayerVector::StateSet::Current, visitor); }; return parentFrameRate; }(); // update parents and children about the vote // First traverse the tree and count how many layers has votes. int layersWithVote = 0; traverseTree([&layersWithVote](Layer* layer) { *transactionNeeded |= setFrameRateForLayerTree(frameRate); // The frame rate is propagated to the children bool childrenHaveFrameRate = false; for (const sp<Layer>& child : mCurrentChildren) { childrenHaveFrameRate |= child->propagateFrameRateForLayerTree(frameRate, transactionNeeded); } // If we don't have a valid frame rate, but the children do, we set this // layer as NoVote to allow the children to control the refresh rate if (!frameRate.rate.isValid() && frameRate.type != FrameRateCompatibility::NoVote && childrenHaveFrameRate) { *transactionNeeded |= setFrameRateForLayerTree(FrameRate(Fps(0.0f), FrameRateCompatibility::NoVote)); } // We return whether this layer ot its children has a vote. We ignore ExactOrMultiple votes for // the same reason we are allowing touch boost for those layers. See // RefreshRateConfigs::getBestRefreshRate for more details. const auto layerVotedWithDefaultCompatibility = layer->mDrawingState.frameRate.rate.isValid() && layer->mDrawingState.frameRate.type == FrameRateCompatibility::Default; const auto layerVotedWithNoVote = layer->mDrawingState.frameRate.type == FrameRateCompatibility::NoVote; frameRate.rate.isValid() && frameRate.type == FrameRateCompatibility::Default; const auto layerVotedWithNoVote = frameRate.type == FrameRateCompatibility::NoVote; const auto layerVotedWithExactCompatibility = layer->mDrawingState.frameRate.type == FrameRateCompatibility::Exact; frameRate.rate.isValid() && frameRate.type == FrameRateCompatibility::Exact; return layerVotedWithDefaultCompatibility || layerVotedWithNoVote || layerVotedWithExactCompatibility || childrenHaveFrameRate; } // We do not count layers that are ExactOrMultiple for the same reason // we are allowing touch boost for those layers. See // RefreshRateConfigs::getBestRefreshRate for more details. if (layerVotedWithDefaultCompatibility || layerVotedWithNoVote || layerVotedWithExactCompatibility) { layersWithVote++; void Layer::updateTreeHasFrameRateVote() { const auto root = [&]() -> sp<Layer> { sp<Layer> layer = this; while (auto parent = layer->getParent()) { layer = parent; } }); return layer; }(); // Now we can update the tree frame rate vote for each layer in the tree const bool treeHasFrameRateVote = layersWithVote > 0; bool transactionNeeded = false; root->propagateFrameRateForLayerTree({}, &transactionNeeded); traverseTree([treeHasFrameRateVote, &transactionNeeded](Layer* layer) { transactionNeeded = layer->updateFrameRateForLayerTree(treeHasFrameRateVote); }); // TODO(b/195668952): we probably don't need eTraversalNeeded here if (transactionNeeded) { mFlinger->setTransactionFlags(eTraversalNeeded); } Loading Loading @@ -1283,13 +1296,15 @@ std::shared_ptr<frametimeline::SurfaceFrame> Layer::createSurfaceFrameForBuffer( return surfaceFrame; } bool Layer::updateFrameRateForLayerTree(bool treeHasFrameRateVote) { const auto updateDrawingState = [&](FrameRate frameRate) { bool Layer::setFrameRateForLayerTree(FrameRate frameRate) { if (mDrawingState.frameRateForLayerTree == frameRate) { return false; } mDrawingState.frameRateForLayerTree = frameRate; // TODO(b/195668952): we probably don't need to dirty visible regions here // or even store frameRateForLayerTree in mDrawingState mDrawingState.sequence++; mDrawingState.modified = true; setTransactionFlags(eTransactionNeeded); Loading @@ -1298,27 +1313,6 @@ bool Layer::updateFrameRateForLayerTree(bool treeHasFrameRateVote) { LayerHistory::LayerUpdateType::SetFrameRate); return true; }; const auto frameRate = mDrawingState.frameRate; if (frameRate.rate.isValid() || frameRate.type == FrameRateCompatibility::NoVote) { return updateDrawingState(frameRate); } // This layer doesn't have a frame rate. Check if its ancestors have a vote for (sp<Layer> parent = getParent(); parent; parent = parent->getParent()) { if (parent->mDrawingState.frameRate.rate.isValid()) { return updateDrawingState(parent->mDrawingState.frameRate); } } // This layer and its ancestors don't have a frame rate. If one of successors // has a vote, return a NoVote for successors to set the vote if (treeHasFrameRateVote) { return updateDrawingState(FrameRate(Fps(0.0f), FrameRateCompatibility::NoVote)); } return updateDrawingState(frameRate); } Layer::FrameRate Layer::getFrameRateForLayerTree() const { Loading
services/surfaceflinger/Layer.h +2 −8 Original line number Diff line number Diff line Loading @@ -702,12 +702,6 @@ public: */ virtual uint32_t doTransaction(uint32_t transactionFlags); /* * Called before updating the drawing state buffer. Used by BufferStateLayer to release any * unlatched buffers in the drawing state. */ virtual void bufferMayChange(const sp<GraphicBuffer>& /* newBuffer */){}; /* * Remove relative z for the layer if its relative parent is not part of the * provided layer tree. Loading Loading @@ -1053,6 +1047,8 @@ private: const std::vector<Layer*>& layersInTree); void updateTreeHasFrameRateVote(); bool propagateFrameRateForLayerTree(FrameRate parentFrameRate, bool* transactionNeeded); bool setFrameRateForLayerTree(FrameRate); void setZOrderRelativeOf(const wp<Layer>& relativeOf); bool isTrustedOverlay() const; Loading @@ -1071,8 +1067,6 @@ private: // Fills in the frame and transform info for the InputWindowInfo void fillInputFrameInfo(InputWindowInfo& info, const ui::Transform& toPhysicalDisplay); bool updateFrameRateForLayerTree(bool treeHasFrameRateVote); // Cached properties computed from drawing state // Effective transform taking into account parent transforms and any parent scaling, which is // a transform from the current layer coordinate space to display(screen) coordinate space. Loading
services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp +35 −0 Original line number Diff line number Diff line Loading @@ -485,5 +485,40 @@ TEST_P(SetFrameRateTest, SetOnParentActivatesTree) { EXPECT_TRUE(FRAME_RATE_VOTE1.rate.equalsWithMargin(layerHistorySummary[1].desiredRefreshRate)); } TEST_P(SetFrameRateTest, addChildForParentWithTreeVote) { EXPECT_CALL(*mMessageQueue, invalidate()).Times(1); const auto& layerFactory = GetParam(); const auto parent = mLayers.emplace_back(layerFactory->createLayer(mFlinger)); const auto child1 = mLayers.emplace_back(layerFactory->createLayer(mFlinger)); const auto child2 = mLayers.emplace_back(layerFactory->createLayer(mFlinger)); const auto childOfChild1 = mLayers.emplace_back(layerFactory->createLayer(mFlinger)); addChild(parent, child1); addChild(child1, childOfChild1); childOfChild1->setFrameRate(FRAME_RATE_VOTE1); commitTransaction(); EXPECT_EQ(FRAME_RATE_TREE, parent->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_VOTE1, childOfChild1->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree()); addChild(parent, child2); commitTransaction(); EXPECT_EQ(FRAME_RATE_TREE, parent->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_VOTE1, childOfChild1->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree()); childOfChild1->setFrameRate(FRAME_RATE_NO_VOTE); commitTransaction(); EXPECT_EQ(FRAME_RATE_NO_VOTE, parent->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_NO_VOTE, child1->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_NO_VOTE, childOfChild1->getFrameRateForLayerTree()); EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree()); } } // namespace } // namespace android