Loading libs/input/input_verifier.rs +1 −0 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ use bitflags::bitflags; use log::info; #[cxx::bridge(namespace = "android::input")] #[allow(unsafe_op_in_unsafe_fn)] mod ffi { #[namespace = "android"] unsafe extern "C++" { Loading services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/TexturePool.h +7 −10 Original line number Diff line number Diff line Loading @@ -66,7 +66,7 @@ public: TexturePool(renderengine::RenderEngine& renderEngine) : mRenderEngine(renderEngine), mEnabled(false) {} virtual ~TexturePool(); virtual ~TexturePool() = default; // Sets the display size for the texture pool. // This will trigger a reallocation for all remaining textures in the pool. Loading @@ -83,10 +83,11 @@ public: // be held by the pool. This is useful when the active display changes. void setEnabled(bool enable); void dump(std::string& out) const EXCLUDES(mMutex); void dump(std::string& out) const; protected: // Proteted visibility so that they can be used for testing const static constexpr size_t kMinPoolSize = 3; const static constexpr size_t kMaxPoolSize = 4; struct Entry { Loading @@ -95,20 +96,16 @@ protected: }; std::deque<Entry> mPool; std::future<std::shared_ptr<renderengine::ExternalTexture>> mGenTextureFuture; private: std::shared_ptr<renderengine::ExternalTexture> genTexture(ui::Size size); std::shared_ptr<renderengine::ExternalTexture> genTexture(); // Returns a previously borrowed texture to the pool. void returnTexture(std::shared_ptr<renderengine::ExternalTexture>&& texture, const sp<Fence>& fence); void genTextureAsyncIfNeeded() REQUIRES(mMutex); void resetPool() REQUIRES(mMutex); renderengine::RenderEngine& mRenderEngine GUARDED_BY(mRenderEngineMutex); ui::Size mSize GUARDED_BY(mMutex); void allocatePool(); renderengine::RenderEngine& mRenderEngine; ui::Size mSize; bool mEnabled; mutable std::mutex mMutex; mutable std::mutex mRenderEngineMutex; }; } // namespace android::compositionengine::impl::planner services/surfaceflinger/CompositionEngine/src/planner/TexturePool.cpp +14 −50 Original line number Diff line number Diff line Loading @@ -25,61 +25,31 @@ namespace android::compositionengine::impl::planner { TexturePool::~TexturePool() { if (mGenTextureFuture.valid()) { mGenTextureFuture.get(); } } void TexturePool::resetPool() { if (mGenTextureFuture.valid()) { mGenTextureFuture.get(); } void TexturePool::allocatePool() { mPool.clear(); genTextureAsyncIfNeeded(); } // Generate a new texture asynchronously so it will not require allocation on the main // thread. void TexturePool::genTextureAsyncIfNeeded() { if (mEnabled && mSize.isValid() && !mGenTextureFuture.valid()) { mGenTextureFuture = std::async( std::launch::async, [&](ui::Size size) { return genTexture(size); }, mSize); if (mEnabled && mSize.isValid()) { mPool.resize(kMinPoolSize); std::generate_n(mPool.begin(), kMinPoolSize, [&]() { return Entry{genTexture(), nullptr}; }); } } void TexturePool::setDisplaySize(ui::Size size) { std::lock_guard lock(mMutex); if (mSize == size) { return; } mSize = size; resetPool(); allocatePool(); } std::shared_ptr<TexturePool::AutoTexture> TexturePool::borrowTexture() { if (mPool.empty()) { std::lock_guard lock(mMutex); std::shared_ptr<TexturePool::AutoTexture> tex; if (mGenTextureFuture.valid()) { tex = std::make_shared<AutoTexture>(*this, mGenTextureFuture.get(), nullptr); } else { tex = std::make_shared<AutoTexture>(*this, genTexture(mSize), nullptr); } // Speculatively generate a new texture, so that the next call does not need // to wait for allocation. genTextureAsyncIfNeeded(); return tex; return std::make_shared<AutoTexture>(*this, genTexture(), nullptr); } const auto entry = mPool.front(); mPool.pop_front(); if (mPool.empty()) { std::lock_guard lock(mMutex); // Similiarly generate a new texture when lending out the last entry, so that // the next call does not need to wait for allocation. genTextureAsyncIfNeeded(); } return std::make_shared<AutoTexture>(*this, entry.texture, entry.fence); } Loading @@ -90,8 +60,6 @@ void TexturePool::returnTexture(std::shared_ptr<renderengine::ExternalTexture>&& return; } std::lock_guard lock(mMutex); // Or the texture on the floor if the pool is no longer tracking textures of the same size. if (static_cast<int32_t>(texture->getBuffer()->getWidth()) != mSize.getWidth() || static_cast<int32_t>(texture->getBuffer()->getHeight()) != mSize.getHeight()) { Loading @@ -112,14 +80,13 @@ void TexturePool::returnTexture(std::shared_ptr<renderengine::ExternalTexture>&& mPool.push_back({std::move(texture), fence}); } std::shared_ptr<renderengine::ExternalTexture> TexturePool::genTexture(ui::Size size) { std::lock_guard lock(mRenderEngineMutex); LOG_ALWAYS_FATAL_IF(!size.isValid(), "Attempted to generate texture with invalid size"); std::shared_ptr<renderengine::ExternalTexture> TexturePool::genTexture() { LOG_ALWAYS_FATAL_IF(!mSize.isValid(), "Attempted to generate texture with invalid size"); return std::make_shared< renderengine::impl:: ExternalTexture>(sp<GraphicBuffer>:: make(static_cast<uint32_t>(size.getWidth()), static_cast<uint32_t>(size.getHeight()), make(static_cast<uint32_t>(mSize.getWidth()), static_cast<uint32_t>(mSize.getHeight()), HAL_PIXEL_FORMAT_RGBA_8888, 1U, static_cast<uint64_t>( GraphicBuffer::USAGE_HW_RENDER | Loading @@ -133,13 +100,10 @@ std::shared_ptr<renderengine::ExternalTexture> TexturePool::genTexture(ui::Size void TexturePool::setEnabled(bool enabled) { mEnabled = enabled; std::lock_guard lock(mMutex); resetPool(); allocatePool(); } void TexturePool::dump(std::string& out) const { std::lock_guard lock(mMutex); base::StringAppendF(&out, "TexturePool (%s) has %zu buffers of size [%" PRId32 ", %" PRId32 "]\n", mEnabled ? "enabled" : "disabled", mPool.size(), mSize.width, mSize.height); Loading services/surfaceflinger/CompositionEngine/tests/planner/TexturePoolTest.cpp +22 −11 Original line number Diff line number Diff line Loading @@ -32,9 +32,9 @@ class TestableTexturePool : public TexturePool { public: TestableTexturePool(renderengine::RenderEngine& renderEngine) : TexturePool(renderEngine) {} size_t getMinPoolSize() const { return kMinPoolSize; } size_t getMaxPoolSize() const { return kMaxPoolSize; } size_t getPoolSize() const { return mPool.size(); } size_t isGenTextureFutureValid() const { return mGenTextureFuture.valid(); } }; struct TexturePoolTest : public testing::Test { Loading @@ -56,8 +56,16 @@ struct TexturePoolTest : public testing::Test { TestableTexturePool mTexturePool = TestableTexturePool(mRenderEngine); }; TEST_F(TexturePoolTest, preallocatesZeroSizePool) { EXPECT_EQ(mTexturePool.getPoolSize(), 0u); TEST_F(TexturePoolTest, preallocatesMinPool) { EXPECT_EQ(mTexturePool.getMinPoolSize(), mTexturePool.getPoolSize()); } TEST_F(TexturePoolTest, doesNotAllocateBeyondMinPool) { for (size_t i = 0; i < mTexturePool.getMinPoolSize() + 1; i++) { auto texture = mTexturePool.borrowTexture(); } EXPECT_EQ(mTexturePool.getMinPoolSize(), mTexturePool.getPoolSize()); } TEST_F(TexturePoolTest, cyclesUpToMaxPoolSize) { Loading Loading @@ -111,10 +119,10 @@ TEST_F(TexturePoolTest, reallocatesWhenDisplaySizeChanges) { static_cast<int32_t>(texture->get()->getBuffer()->getHeight())); mTexturePool.setDisplaySize(kDisplaySizeTwo); EXPECT_EQ(mTexturePool.getPoolSize(), 0u); EXPECT_EQ(mTexturePool.getMinPoolSize(), mTexturePool.getPoolSize()); texture.reset(); // When the texture is returned to the pool, the pool now destroys it. EXPECT_EQ(mTexturePool.getPoolSize(), 0u); EXPECT_EQ(mTexturePool.getMinPoolSize(), mTexturePool.getPoolSize()); texture = mTexturePool.borrowTexture(); EXPECT_EQ(kDisplaySizeTwo.getWidth(), Loading @@ -124,11 +132,14 @@ TEST_F(TexturePoolTest, reallocatesWhenDisplaySizeChanges) { } TEST_F(TexturePoolTest, freesBuffersWhenDisabled) { EXPECT_EQ(mTexturePool.getPoolSize(), mTexturePool.getMinPoolSize()); std::deque<std::shared_ptr<TexturePool::AutoTexture>> textures; for (size_t i = 0; i < 2; i++) { for (size_t i = 0; i < mTexturePool.getMinPoolSize() - 1; i++) { textures.emplace_back(mTexturePool.borrowTexture()); } EXPECT_EQ(mTexturePool.getPoolSize(), 1u); mTexturePool.setEnabled(false); EXPECT_EQ(mTexturePool.getPoolSize(), 0u); Loading @@ -137,11 +148,12 @@ TEST_F(TexturePoolTest, freesBuffersWhenDisabled) { } TEST_F(TexturePoolTest, doesNotHoldBuffersWhenDisabled) { EXPECT_EQ(mTexturePool.getPoolSize(), mTexturePool.getMinPoolSize()); mTexturePool.setEnabled(false); EXPECT_EQ(mTexturePool.getPoolSize(), 0u); std::deque<std::shared_ptr<TexturePool::AutoTexture>> textures; for (size_t i = 0; i < 2; i++) { for (size_t i = 0; i < mTexturePool.getMinPoolSize() - 1; i++) { textures.emplace_back(mTexturePool.borrowTexture()); } Loading @@ -150,13 +162,12 @@ TEST_F(TexturePoolTest, doesNotHoldBuffersWhenDisabled) { EXPECT_EQ(mTexturePool.getPoolSize(), 0u); } TEST_F(TexturePoolTest, genFutureWhenReEnabled) { TEST_F(TexturePoolTest, reallocatesWhenReEnabled) { EXPECT_EQ(mTexturePool.getPoolSize(), mTexturePool.getMinPoolSize()); mTexturePool.setEnabled(false); EXPECT_EQ(mTexturePool.getPoolSize(), 0u); EXPECT_FALSE(mTexturePool.isGenTextureFutureValid()); mTexturePool.setEnabled(true); EXPECT_EQ(mTexturePool.getPoolSize(), 0u); EXPECT_TRUE(mTexturePool.isGenTextureFutureValid()); EXPECT_EQ(mTexturePool.getPoolSize(), mTexturePool.getMinPoolSize()); } } // namespace Loading services/surfaceflinger/Scheduler/RefreshRateSelector.cpp +30 −15 Original line number Diff line number Diff line Loading @@ -148,8 +148,8 @@ std::string toString(const RefreshRateSelector::PolicyVariant& policy) { } // namespace auto RefreshRateSelector::createFrameRateModes( std::function<bool(const DisplayMode&)>&& filterModes, const FpsRange& renderRange) const -> std::vector<FrameRateMode> { const Policy& policy, std::function<bool(const DisplayMode&)>&& filterModes, const FpsRange& renderRange) const -> std::vector<FrameRateMode> { struct Key { Fps fps; int32_t group; Loading Loading @@ -202,11 +202,25 @@ auto RefreshRateSelector::createFrameRateModes( ALOGV("%s: including %s (%s)", __func__, to_string(fps).c_str(), to_string(mode->getFps()).c_str()); } else { // If the primary physical range is a single rate, prefer to stay in that rate // even if there is a lower physical refresh rate available. This would cause more // cases to stay within the primary physical range const Fps existingModeFps = existingIter->second->second->getFps(); const bool existingModeIsPrimaryRange = policy.primaryRangeIsSingleRate() && policy.primaryRanges.physical.includes(existingModeFps); const bool newModeIsPrimaryRange = policy.primaryRangeIsSingleRate() && policy.primaryRanges.physical.includes(mode->getFps()); if (newModeIsPrimaryRange == existingModeIsPrimaryRange) { // We might need to update the map as we found a lower refresh rate if (isStrictlyLess(mode->getFps(), existingIter->second->second->getFps())) { if (isStrictlyLess(mode->getFps(), existingModeFps)) { existingIter->second = it; ALOGV("%s: changing %s (%s)", __func__, to_string(fps).c_str(), to_string(mode->getFps()).c_str()); ALOGV("%s: changing %s (%s) as we found a lower physical rate", __func__, to_string(fps).c_str(), to_string(mode->getFps()).c_str()); } } else if (newModeIsPrimaryRange) { existingIter->second = it; ALOGV("%s: changing %s (%s) to stay in the primary range", __func__, to_string(fps).c_str(), to_string(mode->getFps()).c_str()); } } } Loading Loading @@ -500,10 +514,8 @@ auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vector<LayerRequi // If the primary range consists of a single refresh rate then we can only // move out the of range if layers explicitly request a different refresh // rate. const bool primaryRangeIsSingleRate = isApproxEqual(policy->primaryRanges.physical.min, policy->primaryRanges.physical.max); if (!signals.touch && signals.idle && !(primaryRangeIsSingleRate && hasExplicitVoteLayers)) { if (!signals.touch && signals.idle && !(policy->primaryRangeIsSingleRate() && hasExplicitVoteLayers)) { ALOGV("Idle"); const auto ranking = rankFrameRates(activeMode.getGroup(), RefreshRateOrder::Ascending); ATRACE_FORMAT_INSTANT("%s (Idle)", to_string(ranking.front().frameRateMode.fps).c_str()); Loading Loading @@ -577,8 +589,11 @@ auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vector<LayerRequi continue; } const bool inPrimaryRange = policy->primaryRanges.render.includes(fps); if ((primaryRangeIsSingleRate || !inPrimaryRange) && const bool inPrimaryPhysicalRange = policy->primaryRanges.physical.includes(modePtr->getFps()); const bool inPrimaryRenderRange = policy->primaryRanges.render.includes(fps); if (((policy->primaryRangeIsSingleRate() && !inPrimaryPhysicalRange) || !inPrimaryRenderRange) && !(layer.focused && (layer.vote == LayerVoteType::ExplicitDefault || layer.vote == LayerVoteType::ExplicitExact))) { Loading Loading @@ -689,7 +704,7 @@ auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vector<LayerRequi return score.overallScore == 0; }); if (primaryRangeIsSingleRate) { if (policy->primaryRangeIsSingleRate()) { // If we never scored any layers, then choose the rate from the primary // range instead of picking a random score from the app range. if (noLayerScore) { Loading Loading @@ -1234,14 +1249,14 @@ void RefreshRateSelector::constructAvailableRefreshRates() { (supportsFrameRateOverride() || ranges.render.includes(mode.getFps())); }; auto frameRateModes = createFrameRateModes(filterModes, ranges.render); auto frameRateModes = createFrameRateModes(*policy, filterModes, ranges.render); if (frameRateModes.empty()) { ALOGW("No matching frame rate modes for %s range. policy: %s", rangeName, policy->toString().c_str()); // TODO(b/292105422): Ideally DisplayManager should not send render ranges smaller than // the min supported. See b/292047939. // For not we just ignore the render ranges. frameRateModes = createFrameRateModes(filterModes, {}); frameRateModes = createFrameRateModes(*policy, filterModes, {}); } LOG_ALWAYS_FATAL_IF(frameRateModes.empty(), "No matching frame rate modes for %s range even after ignoring the " Loading Loading
libs/input/input_verifier.rs +1 −0 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ use bitflags::bitflags; use log::info; #[cxx::bridge(namespace = "android::input")] #[allow(unsafe_op_in_unsafe_fn)] mod ffi { #[namespace = "android"] unsafe extern "C++" { Loading
services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/TexturePool.h +7 −10 Original line number Diff line number Diff line Loading @@ -66,7 +66,7 @@ public: TexturePool(renderengine::RenderEngine& renderEngine) : mRenderEngine(renderEngine), mEnabled(false) {} virtual ~TexturePool(); virtual ~TexturePool() = default; // Sets the display size for the texture pool. // This will trigger a reallocation for all remaining textures in the pool. Loading @@ -83,10 +83,11 @@ public: // be held by the pool. This is useful when the active display changes. void setEnabled(bool enable); void dump(std::string& out) const EXCLUDES(mMutex); void dump(std::string& out) const; protected: // Proteted visibility so that they can be used for testing const static constexpr size_t kMinPoolSize = 3; const static constexpr size_t kMaxPoolSize = 4; struct Entry { Loading @@ -95,20 +96,16 @@ protected: }; std::deque<Entry> mPool; std::future<std::shared_ptr<renderengine::ExternalTexture>> mGenTextureFuture; private: std::shared_ptr<renderengine::ExternalTexture> genTexture(ui::Size size); std::shared_ptr<renderengine::ExternalTexture> genTexture(); // Returns a previously borrowed texture to the pool. void returnTexture(std::shared_ptr<renderengine::ExternalTexture>&& texture, const sp<Fence>& fence); void genTextureAsyncIfNeeded() REQUIRES(mMutex); void resetPool() REQUIRES(mMutex); renderengine::RenderEngine& mRenderEngine GUARDED_BY(mRenderEngineMutex); ui::Size mSize GUARDED_BY(mMutex); void allocatePool(); renderengine::RenderEngine& mRenderEngine; ui::Size mSize; bool mEnabled; mutable std::mutex mMutex; mutable std::mutex mRenderEngineMutex; }; } // namespace android::compositionengine::impl::planner
services/surfaceflinger/CompositionEngine/src/planner/TexturePool.cpp +14 −50 Original line number Diff line number Diff line Loading @@ -25,61 +25,31 @@ namespace android::compositionengine::impl::planner { TexturePool::~TexturePool() { if (mGenTextureFuture.valid()) { mGenTextureFuture.get(); } } void TexturePool::resetPool() { if (mGenTextureFuture.valid()) { mGenTextureFuture.get(); } void TexturePool::allocatePool() { mPool.clear(); genTextureAsyncIfNeeded(); } // Generate a new texture asynchronously so it will not require allocation on the main // thread. void TexturePool::genTextureAsyncIfNeeded() { if (mEnabled && mSize.isValid() && !mGenTextureFuture.valid()) { mGenTextureFuture = std::async( std::launch::async, [&](ui::Size size) { return genTexture(size); }, mSize); if (mEnabled && mSize.isValid()) { mPool.resize(kMinPoolSize); std::generate_n(mPool.begin(), kMinPoolSize, [&]() { return Entry{genTexture(), nullptr}; }); } } void TexturePool::setDisplaySize(ui::Size size) { std::lock_guard lock(mMutex); if (mSize == size) { return; } mSize = size; resetPool(); allocatePool(); } std::shared_ptr<TexturePool::AutoTexture> TexturePool::borrowTexture() { if (mPool.empty()) { std::lock_guard lock(mMutex); std::shared_ptr<TexturePool::AutoTexture> tex; if (mGenTextureFuture.valid()) { tex = std::make_shared<AutoTexture>(*this, mGenTextureFuture.get(), nullptr); } else { tex = std::make_shared<AutoTexture>(*this, genTexture(mSize), nullptr); } // Speculatively generate a new texture, so that the next call does not need // to wait for allocation. genTextureAsyncIfNeeded(); return tex; return std::make_shared<AutoTexture>(*this, genTexture(), nullptr); } const auto entry = mPool.front(); mPool.pop_front(); if (mPool.empty()) { std::lock_guard lock(mMutex); // Similiarly generate a new texture when lending out the last entry, so that // the next call does not need to wait for allocation. genTextureAsyncIfNeeded(); } return std::make_shared<AutoTexture>(*this, entry.texture, entry.fence); } Loading @@ -90,8 +60,6 @@ void TexturePool::returnTexture(std::shared_ptr<renderengine::ExternalTexture>&& return; } std::lock_guard lock(mMutex); // Or the texture on the floor if the pool is no longer tracking textures of the same size. if (static_cast<int32_t>(texture->getBuffer()->getWidth()) != mSize.getWidth() || static_cast<int32_t>(texture->getBuffer()->getHeight()) != mSize.getHeight()) { Loading @@ -112,14 +80,13 @@ void TexturePool::returnTexture(std::shared_ptr<renderengine::ExternalTexture>&& mPool.push_back({std::move(texture), fence}); } std::shared_ptr<renderengine::ExternalTexture> TexturePool::genTexture(ui::Size size) { std::lock_guard lock(mRenderEngineMutex); LOG_ALWAYS_FATAL_IF(!size.isValid(), "Attempted to generate texture with invalid size"); std::shared_ptr<renderengine::ExternalTexture> TexturePool::genTexture() { LOG_ALWAYS_FATAL_IF(!mSize.isValid(), "Attempted to generate texture with invalid size"); return std::make_shared< renderengine::impl:: ExternalTexture>(sp<GraphicBuffer>:: make(static_cast<uint32_t>(size.getWidth()), static_cast<uint32_t>(size.getHeight()), make(static_cast<uint32_t>(mSize.getWidth()), static_cast<uint32_t>(mSize.getHeight()), HAL_PIXEL_FORMAT_RGBA_8888, 1U, static_cast<uint64_t>( GraphicBuffer::USAGE_HW_RENDER | Loading @@ -133,13 +100,10 @@ std::shared_ptr<renderengine::ExternalTexture> TexturePool::genTexture(ui::Size void TexturePool::setEnabled(bool enabled) { mEnabled = enabled; std::lock_guard lock(mMutex); resetPool(); allocatePool(); } void TexturePool::dump(std::string& out) const { std::lock_guard lock(mMutex); base::StringAppendF(&out, "TexturePool (%s) has %zu buffers of size [%" PRId32 ", %" PRId32 "]\n", mEnabled ? "enabled" : "disabled", mPool.size(), mSize.width, mSize.height); Loading
services/surfaceflinger/CompositionEngine/tests/planner/TexturePoolTest.cpp +22 −11 Original line number Diff line number Diff line Loading @@ -32,9 +32,9 @@ class TestableTexturePool : public TexturePool { public: TestableTexturePool(renderengine::RenderEngine& renderEngine) : TexturePool(renderEngine) {} size_t getMinPoolSize() const { return kMinPoolSize; } size_t getMaxPoolSize() const { return kMaxPoolSize; } size_t getPoolSize() const { return mPool.size(); } size_t isGenTextureFutureValid() const { return mGenTextureFuture.valid(); } }; struct TexturePoolTest : public testing::Test { Loading @@ -56,8 +56,16 @@ struct TexturePoolTest : public testing::Test { TestableTexturePool mTexturePool = TestableTexturePool(mRenderEngine); }; TEST_F(TexturePoolTest, preallocatesZeroSizePool) { EXPECT_EQ(mTexturePool.getPoolSize(), 0u); TEST_F(TexturePoolTest, preallocatesMinPool) { EXPECT_EQ(mTexturePool.getMinPoolSize(), mTexturePool.getPoolSize()); } TEST_F(TexturePoolTest, doesNotAllocateBeyondMinPool) { for (size_t i = 0; i < mTexturePool.getMinPoolSize() + 1; i++) { auto texture = mTexturePool.borrowTexture(); } EXPECT_EQ(mTexturePool.getMinPoolSize(), mTexturePool.getPoolSize()); } TEST_F(TexturePoolTest, cyclesUpToMaxPoolSize) { Loading Loading @@ -111,10 +119,10 @@ TEST_F(TexturePoolTest, reallocatesWhenDisplaySizeChanges) { static_cast<int32_t>(texture->get()->getBuffer()->getHeight())); mTexturePool.setDisplaySize(kDisplaySizeTwo); EXPECT_EQ(mTexturePool.getPoolSize(), 0u); EXPECT_EQ(mTexturePool.getMinPoolSize(), mTexturePool.getPoolSize()); texture.reset(); // When the texture is returned to the pool, the pool now destroys it. EXPECT_EQ(mTexturePool.getPoolSize(), 0u); EXPECT_EQ(mTexturePool.getMinPoolSize(), mTexturePool.getPoolSize()); texture = mTexturePool.borrowTexture(); EXPECT_EQ(kDisplaySizeTwo.getWidth(), Loading @@ -124,11 +132,14 @@ TEST_F(TexturePoolTest, reallocatesWhenDisplaySizeChanges) { } TEST_F(TexturePoolTest, freesBuffersWhenDisabled) { EXPECT_EQ(mTexturePool.getPoolSize(), mTexturePool.getMinPoolSize()); std::deque<std::shared_ptr<TexturePool::AutoTexture>> textures; for (size_t i = 0; i < 2; i++) { for (size_t i = 0; i < mTexturePool.getMinPoolSize() - 1; i++) { textures.emplace_back(mTexturePool.borrowTexture()); } EXPECT_EQ(mTexturePool.getPoolSize(), 1u); mTexturePool.setEnabled(false); EXPECT_EQ(mTexturePool.getPoolSize(), 0u); Loading @@ -137,11 +148,12 @@ TEST_F(TexturePoolTest, freesBuffersWhenDisabled) { } TEST_F(TexturePoolTest, doesNotHoldBuffersWhenDisabled) { EXPECT_EQ(mTexturePool.getPoolSize(), mTexturePool.getMinPoolSize()); mTexturePool.setEnabled(false); EXPECT_EQ(mTexturePool.getPoolSize(), 0u); std::deque<std::shared_ptr<TexturePool::AutoTexture>> textures; for (size_t i = 0; i < 2; i++) { for (size_t i = 0; i < mTexturePool.getMinPoolSize() - 1; i++) { textures.emplace_back(mTexturePool.borrowTexture()); } Loading @@ -150,13 +162,12 @@ TEST_F(TexturePoolTest, doesNotHoldBuffersWhenDisabled) { EXPECT_EQ(mTexturePool.getPoolSize(), 0u); } TEST_F(TexturePoolTest, genFutureWhenReEnabled) { TEST_F(TexturePoolTest, reallocatesWhenReEnabled) { EXPECT_EQ(mTexturePool.getPoolSize(), mTexturePool.getMinPoolSize()); mTexturePool.setEnabled(false); EXPECT_EQ(mTexturePool.getPoolSize(), 0u); EXPECT_FALSE(mTexturePool.isGenTextureFutureValid()); mTexturePool.setEnabled(true); EXPECT_EQ(mTexturePool.getPoolSize(), 0u); EXPECT_TRUE(mTexturePool.isGenTextureFutureValid()); EXPECT_EQ(mTexturePool.getPoolSize(), mTexturePool.getMinPoolSize()); } } // namespace Loading
services/surfaceflinger/Scheduler/RefreshRateSelector.cpp +30 −15 Original line number Diff line number Diff line Loading @@ -148,8 +148,8 @@ std::string toString(const RefreshRateSelector::PolicyVariant& policy) { } // namespace auto RefreshRateSelector::createFrameRateModes( std::function<bool(const DisplayMode&)>&& filterModes, const FpsRange& renderRange) const -> std::vector<FrameRateMode> { const Policy& policy, std::function<bool(const DisplayMode&)>&& filterModes, const FpsRange& renderRange) const -> std::vector<FrameRateMode> { struct Key { Fps fps; int32_t group; Loading Loading @@ -202,11 +202,25 @@ auto RefreshRateSelector::createFrameRateModes( ALOGV("%s: including %s (%s)", __func__, to_string(fps).c_str(), to_string(mode->getFps()).c_str()); } else { // If the primary physical range is a single rate, prefer to stay in that rate // even if there is a lower physical refresh rate available. This would cause more // cases to stay within the primary physical range const Fps existingModeFps = existingIter->second->second->getFps(); const bool existingModeIsPrimaryRange = policy.primaryRangeIsSingleRate() && policy.primaryRanges.physical.includes(existingModeFps); const bool newModeIsPrimaryRange = policy.primaryRangeIsSingleRate() && policy.primaryRanges.physical.includes(mode->getFps()); if (newModeIsPrimaryRange == existingModeIsPrimaryRange) { // We might need to update the map as we found a lower refresh rate if (isStrictlyLess(mode->getFps(), existingIter->second->second->getFps())) { if (isStrictlyLess(mode->getFps(), existingModeFps)) { existingIter->second = it; ALOGV("%s: changing %s (%s)", __func__, to_string(fps).c_str(), to_string(mode->getFps()).c_str()); ALOGV("%s: changing %s (%s) as we found a lower physical rate", __func__, to_string(fps).c_str(), to_string(mode->getFps()).c_str()); } } else if (newModeIsPrimaryRange) { existingIter->second = it; ALOGV("%s: changing %s (%s) to stay in the primary range", __func__, to_string(fps).c_str(), to_string(mode->getFps()).c_str()); } } } Loading Loading @@ -500,10 +514,8 @@ auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vector<LayerRequi // If the primary range consists of a single refresh rate then we can only // move out the of range if layers explicitly request a different refresh // rate. const bool primaryRangeIsSingleRate = isApproxEqual(policy->primaryRanges.physical.min, policy->primaryRanges.physical.max); if (!signals.touch && signals.idle && !(primaryRangeIsSingleRate && hasExplicitVoteLayers)) { if (!signals.touch && signals.idle && !(policy->primaryRangeIsSingleRate() && hasExplicitVoteLayers)) { ALOGV("Idle"); const auto ranking = rankFrameRates(activeMode.getGroup(), RefreshRateOrder::Ascending); ATRACE_FORMAT_INSTANT("%s (Idle)", to_string(ranking.front().frameRateMode.fps).c_str()); Loading Loading @@ -577,8 +589,11 @@ auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vector<LayerRequi continue; } const bool inPrimaryRange = policy->primaryRanges.render.includes(fps); if ((primaryRangeIsSingleRate || !inPrimaryRange) && const bool inPrimaryPhysicalRange = policy->primaryRanges.physical.includes(modePtr->getFps()); const bool inPrimaryRenderRange = policy->primaryRanges.render.includes(fps); if (((policy->primaryRangeIsSingleRate() && !inPrimaryPhysicalRange) || !inPrimaryRenderRange) && !(layer.focused && (layer.vote == LayerVoteType::ExplicitDefault || layer.vote == LayerVoteType::ExplicitExact))) { Loading Loading @@ -689,7 +704,7 @@ auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vector<LayerRequi return score.overallScore == 0; }); if (primaryRangeIsSingleRate) { if (policy->primaryRangeIsSingleRate()) { // If we never scored any layers, then choose the rate from the primary // range instead of picking a random score from the app range. if (noLayerScore) { Loading Loading @@ -1234,14 +1249,14 @@ void RefreshRateSelector::constructAvailableRefreshRates() { (supportsFrameRateOverride() || ranges.render.includes(mode.getFps())); }; auto frameRateModes = createFrameRateModes(filterModes, ranges.render); auto frameRateModes = createFrameRateModes(*policy, filterModes, ranges.render); if (frameRateModes.empty()) { ALOGW("No matching frame rate modes for %s range. policy: %s", rangeName, policy->toString().c_str()); // TODO(b/292105422): Ideally DisplayManager should not send render ranges smaller than // the min supported. See b/292047939. // For not we just ignore the render ranges. frameRateModes = createFrameRateModes(filterModes, {}); frameRateModes = createFrameRateModes(*policy, filterModes, {}); } LOG_ALWAYS_FATAL_IF(frameRateModes.empty(), "No matching frame rate modes for %s range even after ignoring the " Loading