Maintain the active buffer when clearing buffer slots
When an app discards graphic buffers, for example when a MediaCodec
disconnects from a surface, those buffers will be uncached and removed
from HWC buffer slots. The active buffer, however, should still remain
active until the next buffer is queued up.
Bug: 262037933
Bug: 258196272
Test: atest OutputLayerUncacheBufferTest
Test: atest VtsHalGraphicsComposer3_TargetTest
Test: atest VtsHalGraphicsComposerV2_2TargetTest
Change-Id: I7c4eefb17e8bad694d698f9ad6d1d289f4af8d2c
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index 0ac2d43..766d7ea 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -610,21 +610,27 @@
}
}
-void OutputLayer::uncacheBuffers(std::vector<uint64_t> const& bufferIdsToUncache) {
+void OutputLayer::uncacheBuffers(const std::vector<uint64_t>& bufferIdsToUncache) {
auto& state = editState();
// Skip doing this if there is no HWC interface
if (!state.hwc) {
return;
}
- for (auto bufferId : bufferIdsToUncache) {
+ std::vector<uint32_t> slotsToClear;
+ for (uint64_t bufferId : bufferIdsToUncache) {
uint32_t slot = state.hwc->hwcBufferCache.uncache(bufferId);
- if (slot != UINT32_MAX && state.hwc->hwcLayer) {
- hal::Error error = state.hwc->hwcLayer->clearBufferSlot(slot);
- ALOGE("[%s] Failed to clear buffer slot %d: %s (%d)", getLayerFE().getDebugName(), slot,
- to_string(error).c_str(), static_cast<int32_t>(error));
+ if (slot != UINT32_MAX) {
+ slotsToClear.push_back(slot);
}
}
+
+ hal::Error error =
+ state.hwc->hwcLayer->setBufferSlotsToClear(slotsToClear, state.hwc->activeBufferSlot);
+ if (error != hal::Error::NONE) {
+ ALOGE("[%s] Failed to clear buffer slots: %s (%d)", getLayerFE().getDebugName(),
+ to_string(error).c_str(), static_cast<int32_t>(error));
+ }
}
void OutputLayer::writeBufferStateToHWC(HWC2::Layer* hwcLayer,
@@ -641,15 +647,25 @@
HwcSlotAndBuffer hwcSlotAndBuffer;
sp<Fence> hwcFence;
- // Override buffers use a special cache slot so that they don't evict client buffers.
- if (getState().overrideInfo.buffer != nullptr && !skipLayer) {
- hwcSlotAndBuffer = editState().hwc->hwcBufferCache.getHwcSlotAndBufferForOverride(
- getState().overrideInfo.buffer->getBuffer());
- hwcFence = getState().overrideInfo.acquireFence;
- } else {
- hwcSlotAndBuffer =
- editState().hwc->hwcBufferCache.getHwcSlotAndBuffer(outputIndependentState.buffer);
- hwcFence = outputIndependentState.acquireFence;
+ {
+ // Editing the state only because we update the HWC buffer cache and active buffer.
+ auto& state = editState();
+ // Override buffers use a special cache slot so that they don't evict client buffers.
+ if (state.overrideInfo.buffer != nullptr && !skipLayer) {
+ hwcSlotAndBuffer = state.hwc->hwcBufferCache.getOverrideHwcSlotAndBuffer(
+ state.overrideInfo.buffer->getBuffer());
+ hwcFence = state.overrideInfo.acquireFence;
+ } else {
+ hwcSlotAndBuffer =
+ state.hwc->hwcBufferCache.getHwcSlotAndBuffer(outputIndependentState.buffer);
+ hwcFence = outputIndependentState.acquireFence;
+ }
+
+ // Keep track of the active buffer slot, so we can restore it after clearing other buffer
+ // slots.
+ if (hwcSlotAndBuffer.buffer) {
+ state.hwc->activeBufferSlot = hwcSlotAndBuffer.slot;
+ }
}
if (auto error = hwcLayer->setBuffer(hwcSlotAndBuffer.slot, hwcSlotAndBuffer.buffer, hwcFence);