Loading services/surfaceflinger/BufferQueueLayer.cpp +5 −1 Original line number Diff line number Diff line Loading @@ -361,8 +361,12 @@ void BufferQueueLayer::setHwcLayerBuffer(const sp<const DisplayDevice>& display) uint32_t hwcSlot = 0; sp<GraphicBuffer> hwcBuffer; // INVALID_BUFFER_SLOT is used to identify BufferStateLayers. Default to 0 // for BufferQueueLayers int slot = (mActiveBufferSlot == BufferQueue::INVALID_BUFFER_SLOT) ? 0 : mActiveBufferSlot; (*outputLayer->editState().hwc) .hwcBufferCache.getHwcBuffer(mActiveBuffer, &hwcSlot, &hwcBuffer); .hwcBufferCache.getHwcBuffer(slot, mActiveBuffer, &hwcSlot, &hwcBuffer); auto acquireFence = mConsumer->getCurrentFence(); auto error = hwcLayer->setBuffer(hwcSlot, hwcBuffer, acquireFence); Loading services/surfaceflinger/BufferStateLayer.cpp +3 −3 Original line number Diff line number Diff line Loading @@ -585,10 +585,10 @@ void BufferStateLayer::setHwcLayerBuffer(const sp<const DisplayDevice>& display) const State& s(getDrawingState()); // obtain slot uint32_t hwcSlot = 0; uint32_t hwcSlot; sp<GraphicBuffer> buffer; hwcInfo.hwcBufferCache.getHwcBuffer(s.buffer, &hwcSlot, &buffer); hwcInfo.hwcBufferCache.getHwcBuffer(BufferQueue::INVALID_BUFFER_SLOT, s.buffer, &hwcSlot, &buffer); auto error = hwcLayer->setBuffer(hwcSlot, buffer, s.acquireFence); if (error != HWC2::Error::None) { Loading services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcBufferCache.h +1 −1 Original line number Diff line number Diff line Loading @@ -45,7 +45,7 @@ public: // // outBuffer is set to buffer when buffer is not in the HWC cache; // otherwise, outBuffer is set to nullptr. void getHwcBuffer(const sp<GraphicBuffer>& buffer, uint32_t* outSlot, void getHwcBuffer(int slot, const sp<GraphicBuffer>& buffer, uint32_t* outSlot, sp<GraphicBuffer>* outBuffer); protected: Loading services/surfaceflinger/CompositionEngine/src/HwcBufferCache.cpp +11 −3 Original line number Diff line number Diff line Loading @@ -48,12 +48,20 @@ uint32_t HwcBufferCache::getLeastRecentlyUsedSlot() { return std::distance(std::begin(mBuffers), iter); } void HwcBufferCache::getHwcBuffer(const sp<GraphicBuffer>& buffer, uint32_t* outSlot, void HwcBufferCache::getHwcBuffer(int slot, const sp<GraphicBuffer>& buffer, uint32_t* outSlot, sp<GraphicBuffer>* outBuffer) { bool cached = getSlot(buffer, outSlot); // if this slot corresponds to a BufferStateLayer, generate the slot if (slot == BufferQueue::INVALID_BUFFER_SLOT) { getSlot(buffer, outSlot); } else if (slot < 0 || slot >= BufferQueue::NUM_BUFFER_SLOTS) { *outSlot = 0; } else { *outSlot = slot; } auto& [currentCounter, currentBuffer] = mBuffers[*outSlot]; if (cached) { wp<GraphicBuffer> weakCopy(buffer); if (currentBuffer == weakCopy) { // already cached in HWC, skip sending the buffer *outBuffer = nullptr; currentCounter = getCounter(); Loading services/surfaceflinger/CompositionEngine/tests/HwcBufferCacheTest.cpp +60 −36 Original line number Diff line number Diff line Loading @@ -24,9 +24,9 @@ namespace { class TestableHwcBufferCache : public impl::HwcBufferCache { public: void getHwcBuffer(const sp<GraphicBuffer>& buffer, uint32_t* outSlot, void getHwcBuffer(int slot, const sp<GraphicBuffer>& buffer, uint32_t* outSlot, sp<GraphicBuffer>* outBuffer) { HwcBufferCache::getHwcBuffer(buffer, outSlot, outBuffer); HwcBufferCache::getHwcBuffer(slot, buffer, outSlot, outBuffer); } bool getSlot(const sp<GraphicBuffer>& buffer, uint32_t* outSlot) { return HwcBufferCache::getSlot(buffer, outSlot); Loading @@ -38,64 +38,88 @@ class HwcBufferCacheTest : public testing::Test { public: ~HwcBufferCacheTest() override = default; TestableHwcBufferCache mCache; sp<GraphicBuffer> mBuffer1{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; sp<GraphicBuffer> mBuffer2{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; }; TEST_F(HwcBufferCacheTest, testSlot) { void testSlot(const int inSlot, const uint32_t expectedSlot) { uint32_t outSlot; sp<GraphicBuffer> outBuffer; // The first time, the output is the same as the input mCache.getHwcBuffer(mBuffer1, &outSlot, &outBuffer); EXPECT_EQ(0, outSlot); mCache.getHwcBuffer(inSlot, mBuffer1, &outSlot, &outBuffer); EXPECT_EQ(expectedSlot, outSlot); EXPECT_EQ(mBuffer1, outBuffer); // The second time with the same buffer, the outBuffer is nullptr. mCache.getHwcBuffer(mBuffer1, &outSlot, &outBuffer); EXPECT_EQ(0, outSlot); mCache.getHwcBuffer(inSlot, mBuffer1, &outSlot, &outBuffer); EXPECT_EQ(expectedSlot, outSlot); EXPECT_EQ(nullptr, outBuffer.get()); // With a new buffer, the outBuffer is the input. mCache.getHwcBuffer(mBuffer2, &outSlot, &outBuffer); EXPECT_EQ(1, outSlot); mCache.getHwcBuffer(inSlot, mBuffer2, &outSlot, &outBuffer); EXPECT_EQ(expectedSlot, outSlot); EXPECT_EQ(mBuffer2, outBuffer); // Again, the second request with the same buffer sets outBuffer to nullptr. mCache.getHwcBuffer(mBuffer2, &outSlot, &outBuffer); EXPECT_EQ(1, outSlot); mCache.getHwcBuffer(inSlot, mBuffer2, &outSlot, &outBuffer); EXPECT_EQ(expectedSlot, outSlot); EXPECT_EQ(nullptr, outBuffer.get()); // Setting a slot to use nullptr lookslike works, but note that // the output values make it look like no new buffer is being set.... mCache.getHwcBuffer(sp<GraphicBuffer>(), &outSlot, &outBuffer); EXPECT_EQ(2, outSlot); mCache.getHwcBuffer(inSlot, sp<GraphicBuffer>(), &outSlot, &outBuffer); EXPECT_EQ(expectedSlot, outSlot); EXPECT_EQ(nullptr, outBuffer.get()); } TEST_F(HwcBufferCacheTest, testGetLeastRecentlyUsedSlot) { int slot; uint32_t outSlot; sp<GraphicBuffer> outBuffer; impl::HwcBufferCache mCache; sp<GraphicBuffer> mBuffer1{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; sp<GraphicBuffer> mBuffer2{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; }; TEST_F(HwcBufferCacheTest, cacheWorksForSlotZero) { testSlot(0, 0); } TEST_F(HwcBufferCacheTest, cacheWorksForMaxSlot) { testSlot(BufferQueue::NUM_BUFFER_SLOTS - 1, BufferQueue::NUM_BUFFER_SLOTS - 1); } // fill up cache for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) { sp<GraphicBuffer> buf{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; mCache.getHwcBuffer(buf, &outSlot, &outBuffer); EXPECT_EQ(buf, outBuffer); EXPECT_EQ(i, outSlot); TEST_F(HwcBufferCacheTest, cacheMapsNegativeSlotToZero) { testSlot(-123, 0); } slot = mCache.getLeastRecentlyUsedSlot(); EXPECT_EQ(0, slot); TEST_F(HwcBufferCacheTest, cacheGeneratesSlotForInvalidBufferSlot) { uint32_t outSlot; sp<GraphicBuffer> outBuffer; mCache.getHwcBuffer(BufferQueue::INVALID_BUFFER_SLOT, mBuffer1, &outSlot, &outBuffer); EXPECT_EQ(0, outSlot); EXPECT_EQ(mBuffer1, outBuffer); mCache.getHwcBuffer(mBuffer1, &outSlot, &outBuffer); mCache.getHwcBuffer(BufferQueue::INVALID_BUFFER_SLOT, mBuffer1, &outSlot, &outBuffer); EXPECT_EQ(0, outSlot); EXPECT_EQ(nullptr, outBuffer.get()); mCache.getHwcBuffer(BufferQueue::INVALID_BUFFER_SLOT, mBuffer2, &outSlot, &outBuffer); EXPECT_EQ(1, outSlot); EXPECT_EQ(mBuffer2, outBuffer); mCache.getHwcBuffer(BufferQueue::INVALID_BUFFER_SLOT, mBuffer2, &outSlot, &outBuffer); EXPECT_EQ(1, outSlot); EXPECT_EQ(nullptr, outBuffer.get()); mCache.getHwcBuffer(BufferQueue::INVALID_BUFFER_SLOT, sp<GraphicBuffer>(), &outSlot, &outBuffer); EXPECT_EQ(2, outSlot); EXPECT_EQ(nullptr, outBuffer.get()); // note that sending mBuffer1 with explicit slot 1 will overwrite mBuffer2 // and also cause mBuffer1 to be stored in two places mCache.getHwcBuffer(1, mBuffer1, &outSlot, &outBuffer); EXPECT_EQ(1, outSlot); EXPECT_EQ(mBuffer1, outBuffer); slot = mCache.getLeastRecentlyUsedSlot(); EXPECT_EQ(1, slot); mCache.getHwcBuffer(BufferQueue::INVALID_BUFFER_SLOT, mBuffer2, &outSlot, &outBuffer); EXPECT_EQ(3, outSlot); EXPECT_EQ(mBuffer2, outBuffer); } } // namespace Loading Loading
services/surfaceflinger/BufferQueueLayer.cpp +5 −1 Original line number Diff line number Diff line Loading @@ -361,8 +361,12 @@ void BufferQueueLayer::setHwcLayerBuffer(const sp<const DisplayDevice>& display) uint32_t hwcSlot = 0; sp<GraphicBuffer> hwcBuffer; // INVALID_BUFFER_SLOT is used to identify BufferStateLayers. Default to 0 // for BufferQueueLayers int slot = (mActiveBufferSlot == BufferQueue::INVALID_BUFFER_SLOT) ? 0 : mActiveBufferSlot; (*outputLayer->editState().hwc) .hwcBufferCache.getHwcBuffer(mActiveBuffer, &hwcSlot, &hwcBuffer); .hwcBufferCache.getHwcBuffer(slot, mActiveBuffer, &hwcSlot, &hwcBuffer); auto acquireFence = mConsumer->getCurrentFence(); auto error = hwcLayer->setBuffer(hwcSlot, hwcBuffer, acquireFence); Loading
services/surfaceflinger/BufferStateLayer.cpp +3 −3 Original line number Diff line number Diff line Loading @@ -585,10 +585,10 @@ void BufferStateLayer::setHwcLayerBuffer(const sp<const DisplayDevice>& display) const State& s(getDrawingState()); // obtain slot uint32_t hwcSlot = 0; uint32_t hwcSlot; sp<GraphicBuffer> buffer; hwcInfo.hwcBufferCache.getHwcBuffer(s.buffer, &hwcSlot, &buffer); hwcInfo.hwcBufferCache.getHwcBuffer(BufferQueue::INVALID_BUFFER_SLOT, s.buffer, &hwcSlot, &buffer); auto error = hwcLayer->setBuffer(hwcSlot, buffer, s.acquireFence); if (error != HWC2::Error::None) { Loading
services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcBufferCache.h +1 −1 Original line number Diff line number Diff line Loading @@ -45,7 +45,7 @@ public: // // outBuffer is set to buffer when buffer is not in the HWC cache; // otherwise, outBuffer is set to nullptr. void getHwcBuffer(const sp<GraphicBuffer>& buffer, uint32_t* outSlot, void getHwcBuffer(int slot, const sp<GraphicBuffer>& buffer, uint32_t* outSlot, sp<GraphicBuffer>* outBuffer); protected: Loading
services/surfaceflinger/CompositionEngine/src/HwcBufferCache.cpp +11 −3 Original line number Diff line number Diff line Loading @@ -48,12 +48,20 @@ uint32_t HwcBufferCache::getLeastRecentlyUsedSlot() { return std::distance(std::begin(mBuffers), iter); } void HwcBufferCache::getHwcBuffer(const sp<GraphicBuffer>& buffer, uint32_t* outSlot, void HwcBufferCache::getHwcBuffer(int slot, const sp<GraphicBuffer>& buffer, uint32_t* outSlot, sp<GraphicBuffer>* outBuffer) { bool cached = getSlot(buffer, outSlot); // if this slot corresponds to a BufferStateLayer, generate the slot if (slot == BufferQueue::INVALID_BUFFER_SLOT) { getSlot(buffer, outSlot); } else if (slot < 0 || slot >= BufferQueue::NUM_BUFFER_SLOTS) { *outSlot = 0; } else { *outSlot = slot; } auto& [currentCounter, currentBuffer] = mBuffers[*outSlot]; if (cached) { wp<GraphicBuffer> weakCopy(buffer); if (currentBuffer == weakCopy) { // already cached in HWC, skip sending the buffer *outBuffer = nullptr; currentCounter = getCounter(); Loading
services/surfaceflinger/CompositionEngine/tests/HwcBufferCacheTest.cpp +60 −36 Original line number Diff line number Diff line Loading @@ -24,9 +24,9 @@ namespace { class TestableHwcBufferCache : public impl::HwcBufferCache { public: void getHwcBuffer(const sp<GraphicBuffer>& buffer, uint32_t* outSlot, void getHwcBuffer(int slot, const sp<GraphicBuffer>& buffer, uint32_t* outSlot, sp<GraphicBuffer>* outBuffer) { HwcBufferCache::getHwcBuffer(buffer, outSlot, outBuffer); HwcBufferCache::getHwcBuffer(slot, buffer, outSlot, outBuffer); } bool getSlot(const sp<GraphicBuffer>& buffer, uint32_t* outSlot) { return HwcBufferCache::getSlot(buffer, outSlot); Loading @@ -38,64 +38,88 @@ class HwcBufferCacheTest : public testing::Test { public: ~HwcBufferCacheTest() override = default; TestableHwcBufferCache mCache; sp<GraphicBuffer> mBuffer1{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; sp<GraphicBuffer> mBuffer2{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; }; TEST_F(HwcBufferCacheTest, testSlot) { void testSlot(const int inSlot, const uint32_t expectedSlot) { uint32_t outSlot; sp<GraphicBuffer> outBuffer; // The first time, the output is the same as the input mCache.getHwcBuffer(mBuffer1, &outSlot, &outBuffer); EXPECT_EQ(0, outSlot); mCache.getHwcBuffer(inSlot, mBuffer1, &outSlot, &outBuffer); EXPECT_EQ(expectedSlot, outSlot); EXPECT_EQ(mBuffer1, outBuffer); // The second time with the same buffer, the outBuffer is nullptr. mCache.getHwcBuffer(mBuffer1, &outSlot, &outBuffer); EXPECT_EQ(0, outSlot); mCache.getHwcBuffer(inSlot, mBuffer1, &outSlot, &outBuffer); EXPECT_EQ(expectedSlot, outSlot); EXPECT_EQ(nullptr, outBuffer.get()); // With a new buffer, the outBuffer is the input. mCache.getHwcBuffer(mBuffer2, &outSlot, &outBuffer); EXPECT_EQ(1, outSlot); mCache.getHwcBuffer(inSlot, mBuffer2, &outSlot, &outBuffer); EXPECT_EQ(expectedSlot, outSlot); EXPECT_EQ(mBuffer2, outBuffer); // Again, the second request with the same buffer sets outBuffer to nullptr. mCache.getHwcBuffer(mBuffer2, &outSlot, &outBuffer); EXPECT_EQ(1, outSlot); mCache.getHwcBuffer(inSlot, mBuffer2, &outSlot, &outBuffer); EXPECT_EQ(expectedSlot, outSlot); EXPECT_EQ(nullptr, outBuffer.get()); // Setting a slot to use nullptr lookslike works, but note that // the output values make it look like no new buffer is being set.... mCache.getHwcBuffer(sp<GraphicBuffer>(), &outSlot, &outBuffer); EXPECT_EQ(2, outSlot); mCache.getHwcBuffer(inSlot, sp<GraphicBuffer>(), &outSlot, &outBuffer); EXPECT_EQ(expectedSlot, outSlot); EXPECT_EQ(nullptr, outBuffer.get()); } TEST_F(HwcBufferCacheTest, testGetLeastRecentlyUsedSlot) { int slot; uint32_t outSlot; sp<GraphicBuffer> outBuffer; impl::HwcBufferCache mCache; sp<GraphicBuffer> mBuffer1{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; sp<GraphicBuffer> mBuffer2{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; }; TEST_F(HwcBufferCacheTest, cacheWorksForSlotZero) { testSlot(0, 0); } TEST_F(HwcBufferCacheTest, cacheWorksForMaxSlot) { testSlot(BufferQueue::NUM_BUFFER_SLOTS - 1, BufferQueue::NUM_BUFFER_SLOTS - 1); } // fill up cache for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) { sp<GraphicBuffer> buf{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)}; mCache.getHwcBuffer(buf, &outSlot, &outBuffer); EXPECT_EQ(buf, outBuffer); EXPECT_EQ(i, outSlot); TEST_F(HwcBufferCacheTest, cacheMapsNegativeSlotToZero) { testSlot(-123, 0); } slot = mCache.getLeastRecentlyUsedSlot(); EXPECT_EQ(0, slot); TEST_F(HwcBufferCacheTest, cacheGeneratesSlotForInvalidBufferSlot) { uint32_t outSlot; sp<GraphicBuffer> outBuffer; mCache.getHwcBuffer(BufferQueue::INVALID_BUFFER_SLOT, mBuffer1, &outSlot, &outBuffer); EXPECT_EQ(0, outSlot); EXPECT_EQ(mBuffer1, outBuffer); mCache.getHwcBuffer(mBuffer1, &outSlot, &outBuffer); mCache.getHwcBuffer(BufferQueue::INVALID_BUFFER_SLOT, mBuffer1, &outSlot, &outBuffer); EXPECT_EQ(0, outSlot); EXPECT_EQ(nullptr, outBuffer.get()); mCache.getHwcBuffer(BufferQueue::INVALID_BUFFER_SLOT, mBuffer2, &outSlot, &outBuffer); EXPECT_EQ(1, outSlot); EXPECT_EQ(mBuffer2, outBuffer); mCache.getHwcBuffer(BufferQueue::INVALID_BUFFER_SLOT, mBuffer2, &outSlot, &outBuffer); EXPECT_EQ(1, outSlot); EXPECT_EQ(nullptr, outBuffer.get()); mCache.getHwcBuffer(BufferQueue::INVALID_BUFFER_SLOT, sp<GraphicBuffer>(), &outSlot, &outBuffer); EXPECT_EQ(2, outSlot); EXPECT_EQ(nullptr, outBuffer.get()); // note that sending mBuffer1 with explicit slot 1 will overwrite mBuffer2 // and also cause mBuffer1 to be stored in two places mCache.getHwcBuffer(1, mBuffer1, &outSlot, &outBuffer); EXPECT_EQ(1, outSlot); EXPECT_EQ(mBuffer1, outBuffer); slot = mCache.getLeastRecentlyUsedSlot(); EXPECT_EQ(1, slot); mCache.getHwcBuffer(BufferQueue::INVALID_BUFFER_SLOT, mBuffer2, &outSlot, &outBuffer); EXPECT_EQ(3, outSlot); EXPECT_EQ(mBuffer2, outBuffer); } } // namespace Loading