Introduce a dependency monitor for fences
This allows for userspace logging for a buffer and read/write dependencies on the buffer.
Hook up SF to the dependency monitor.
Right now this _does_ emit logs in SF when the primary display is powered down, which is likely indicative of SF being sloppy about release fences in situations where tearing won't be noticeable, but I did verify that manually making screenshotting forget to merge GPU work into a layer's release fence, which has been one way SF's torn the screen, triggers logcat, which is ultimately what we want.
Bug: 360932099
Flag: com.android.graphics.surfaceflinger.flags.monitor_buffer_fences
Test: manually remove screenshot fence handling and check logs
Change-Id: Ica391dfa8a4f2924bb72664b9d9399e4ad9e1747
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
index 780758e..e2ea0f1 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
@@ -167,6 +167,8 @@
// Checks if the buffer's release fence has been set
virtual LayerFE::ReleaseFencePromiseStatus getReleaseFencePromiseStatus() = 0;
+ virtual void setReleasedBuffer(sp<GraphicBuffer> buffer) = 0;
+
// Indicates that the picture profile request was applied to this layer.
virtual void onPictureProfileCommitted() = 0;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
index d2a5a20..f65a908 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
@@ -52,6 +52,7 @@
MOCK_METHOD0(createReleaseFenceFuture, ftl::Future<FenceResult>());
MOCK_METHOD1(setReleaseFence, void(const FenceResult&));
+ MOCK_METHOD1(setReleasedBuffer, void(sp<GraphicBuffer>));
MOCK_METHOD0(getReleaseFencePromiseStatus, LayerFE::ReleaseFencePromiseStatus());
MOCK_CONST_METHOD0(getDebugName, const char*());
MOCK_CONST_METHOD0(getSequence, int32_t());
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 25f6436..00a61a5 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -1676,6 +1676,7 @@
Fence::merge("LayerRelease", releaseFence, frame.clientTargetAcquireFence);
}
layer->getLayerFE().setReleaseFence(releaseFence);
+ layer->getLayerFE().setReleasedBuffer(layer->getLayerFE().getCompositionState()->buffer);
}
// We've got a list of layers needing fences, that are disjoint with
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index b56147a..590626a 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -3314,6 +3314,17 @@
sp<Fence> layer2Fence = sp<Fence>::make();
sp<Fence> layer3Fence = sp<Fence>::make();
+ // Set up layerfe buffers
+ LayerFECompositionState layer1State;
+ layer1State.buffer = sp<GraphicBuffer>::make();
+ LayerFECompositionState layer2State;
+ layer2State.buffer = sp<GraphicBuffer>::make();
+ LayerFECompositionState layer3State;
+ layer3State.buffer = nullptr;
+ EXPECT_CALL(*mLayer1.layerFE, getCompositionState()).WillOnce(Return(&layer1State));
+ EXPECT_CALL(*mLayer2.layerFE, getCompositionState()).WillOnce(Return(&layer2State));
+ EXPECT_CALL(*mLayer3.layerFE, getCompositionState()).WillOnce(Return(&layer3State));
+
Output::FrameFences frameFences;
frameFences.layerFences.emplace(&mLayer1.hwc2Layer, layer1Fence);
frameFences.layerFences.emplace(&mLayer2.hwc2Layer, layer2Fence);
@@ -3330,14 +3341,23 @@
.WillOnce([&layer1Fence](FenceResult releaseFence) {
EXPECT_EQ(FenceResult(layer1Fence), releaseFence);
});
+ EXPECT_CALL(*mLayer1.layerFE, setReleasedBuffer(_)).WillOnce([&](sp<GraphicBuffer> buffer) {
+ EXPECT_EQ(layer1State.buffer, buffer);
+ });
EXPECT_CALL(*mLayer2.layerFE, setReleaseFence(_))
.WillOnce([&layer2Fence](FenceResult releaseFence) {
EXPECT_EQ(FenceResult(layer2Fence), releaseFence);
});
+ EXPECT_CALL(*mLayer2.layerFE, setReleasedBuffer(_)).WillOnce([&](sp<GraphicBuffer> buffer) {
+ EXPECT_EQ(layer2State.buffer, buffer);
+ });
EXPECT_CALL(*mLayer3.layerFE, setReleaseFence(_))
.WillOnce([&layer3Fence](FenceResult releaseFence) {
EXPECT_EQ(FenceResult(layer3Fence), releaseFence);
});
+ EXPECT_CALL(*mLayer3.layerFE, setReleasedBuffer(_)).WillOnce([&](sp<GraphicBuffer> buffer) {
+ EXPECT_EQ(layer3State.buffer, buffer);
+ });
constexpr bool kFlushEvenWhenDisabled = false;
mOutput.presentFrameAndReleaseLayers(kFlushEvenWhenDisabled);
@@ -3353,6 +3373,17 @@
frameFences.layerFences.emplace(&mLayer2.hwc2Layer, sp<Fence>::make());
frameFences.layerFences.emplace(&mLayer3.hwc2Layer, sp<Fence>::make());
+ // Set up layerfe buffers
+ LayerFECompositionState layer1State;
+ layer1State.buffer = sp<GraphicBuffer>::make();
+ LayerFECompositionState layer2State;
+ layer2State.buffer = sp<GraphicBuffer>::make();
+ LayerFECompositionState layer3State;
+ layer3State.buffer = nullptr;
+ EXPECT_CALL(*mLayer1.layerFE, getCompositionState()).WillOnce(Return(&layer1State));
+ EXPECT_CALL(*mLayer2.layerFE, getCompositionState()).WillOnce(Return(&layer2State));
+ EXPECT_CALL(*mLayer3.layerFE, getCompositionState()).WillOnce(Return(&layer3State));
+
EXPECT_CALL(mOutput, presentFrame()).WillOnce(Return(frameFences));
EXPECT_CALL(*mRenderSurface, onPresentDisplayCompleted());
@@ -3362,6 +3393,15 @@
EXPECT_CALL(*mLayer1.layerFE, setReleaseFence).WillOnce(Return());
EXPECT_CALL(*mLayer2.layerFE, setReleaseFence).WillOnce(Return());
EXPECT_CALL(*mLayer3.layerFE, setReleaseFence).WillOnce(Return());
+ EXPECT_CALL(*mLayer1.layerFE, setReleasedBuffer(_)).WillOnce([&](sp<GraphicBuffer> buffer) {
+ EXPECT_EQ(layer1State.buffer, buffer);
+ });
+ EXPECT_CALL(*mLayer2.layerFE, setReleasedBuffer(_)).WillOnce([&](sp<GraphicBuffer> buffer) {
+ EXPECT_EQ(layer2State.buffer, buffer);
+ });
+ EXPECT_CALL(*mLayer3.layerFE, setReleasedBuffer(_)).WillOnce([&](sp<GraphicBuffer> buffer) {
+ EXPECT_EQ(layer3State.buffer, buffer);
+ });
constexpr bool kFlushEvenWhenDisabled = false;
mOutput.presentFrameAndReleaseLayers(kFlushEvenWhenDisabled);
}
@@ -3404,7 +3444,6 @@
.WillOnce([&presentFence](FenceResult fenceResult) {
EXPECT_EQ(FenceResult(presentFence), fenceResult);
});
-
constexpr bool kFlushEvenWhenDisabled = false;
mOutput.presentFrameAndReleaseLayers(kFlushEvenWhenDisabled);
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 3a884d6..2e31282 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -722,6 +722,10 @@
uint32_t currentMaxAcquiredBufferCount =
mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate(mOwnerUid);
+ if (FlagManager::getInstance().monitor_buffer_fences()) {
+ buffer->getDependencyMonitor().addEgress(FenceTime::makeValid(fence), "Layer release");
+ }
+
if (listener) {
listener->onReleaseBuffer(callbackId, fence, currentMaxAcquiredBufferCount);
}
@@ -940,6 +944,7 @@
std::max(mDrawingState.frameNumber, mDrawingState.barrierFrameNumber);
mDrawingState.releaseBufferListener = bufferData.releaseBufferListener;
+ mDrawingState.previousBuffer = std::move(mDrawingState.buffer);
mDrawingState.buffer = std::move(buffer);
mDrawingState.acquireFence = bufferData.flags.test(BufferData::BufferDataChange::fenceChanged)
? bufferData.acquireFence
@@ -1122,6 +1127,7 @@
handle->acquireTimeOrFence = mCallbackHandleAcquireTimeOrFence;
handle->frameNumber = mDrawingState.frameNumber;
handle->previousFrameNumber = mDrawingState.previousFrameNumber;
+ handle->previousBuffer = mDrawingState.previousBuffer;
if (mPreviousReleaseBufferEndpoint == handle->listener) {
// Add fence from previous screenshot now so that it can be dispatched to the
// client.
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 081bb22..88754f9 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -117,6 +117,7 @@
uint32_t bufferTransform;
bool transformToDisplayInverse;
Region transparentRegionHint;
+ std::shared_ptr<renderengine::ExternalTexture> previousBuffer;
std::shared_ptr<renderengine::ExternalTexture> buffer;
sp<Fence> acquireFence;
std::shared_ptr<FenceTime> acquireFenceTime;
diff --git a/services/surfaceflinger/LayerFE.cpp b/services/surfaceflinger/LayerFE.cpp
index b619268..5e076bd 100644
--- a/services/surfaceflinger/LayerFE.cpp
+++ b/services/surfaceflinger/LayerFE.cpp
@@ -410,6 +410,15 @@
if (mReleaseFencePromiseStatus == ReleaseFencePromiseStatus::FULFILLED) {
return;
}
+
+ if (releaseFence.has_value()) {
+ if (FlagManager::getInstance().monitor_buffer_fences()) {
+ if (auto strongBuffer = mReleasedBuffer.promote()) {
+ strongBuffer->getDependencyMonitor()
+ .addAccessCompletion(FenceTime::makeValid(releaseFence.value()), "HWC");
+ }
+ }
+ }
mReleaseFence.set_value(releaseFence);
mReleaseFencePromiseStatus = ReleaseFencePromiseStatus::FULFILLED;
}
@@ -428,6 +437,10 @@
return mReleaseFencePromiseStatus;
}
+void LayerFE::setReleasedBuffer(sp<GraphicBuffer> buffer) {
+ mReleasedBuffer = std::move(buffer);
+}
+
void LayerFE::setLastHwcState(const LayerFE::HwcLayerDebugState &state) {
mLastHwcState = state;
}
diff --git a/services/surfaceflinger/LayerFE.h b/services/surfaceflinger/LayerFE.h
index a537456..b89b6b4 100644
--- a/services/surfaceflinger/LayerFE.h
+++ b/services/surfaceflinger/LayerFE.h
@@ -18,6 +18,7 @@
#include <android/gui/CachingHint.h>
#include <gui/LayerMetadata.h>
+#include <ui/GraphicBuffer.h>
#include <ui/LayerStack.h>
#include <ui/PictureProfileHandle.h>
@@ -58,6 +59,7 @@
ftl::Future<FenceResult> createReleaseFenceFuture() override;
void setReleaseFence(const FenceResult& releaseFence) override;
LayerFE::ReleaseFencePromiseStatus getReleaseFencePromiseStatus() override;
+ void setReleasedBuffer(sp<GraphicBuffer> buffer) override;
void onPictureProfileCommitted() override;
// Used for debugging purposes, e.g. perfetto tracing, dumpsys.
@@ -95,6 +97,7 @@
std::promise<FenceResult> mReleaseFence;
ReleaseFencePromiseStatus mReleaseFencePromiseStatus = ReleaseFencePromiseStatus::UNINITIALIZED;
HwcLayerDebugState mLastHwcState;
+ wp<GraphicBuffer> mReleasedBuffer;
};
} // namespace android
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 780b897..14ec41f 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -5088,6 +5088,12 @@
layerName.c_str(), transactionState.getId());
if (resolvedState.externalTexture) {
resolvedState.state.bufferData->buffer = resolvedState.externalTexture->getBuffer();
+ if (FlagManager::getInstance().monitor_buffer_fences()) {
+ resolvedState.state.bufferData->buffer->getDependencyMonitor()
+ .addIngress(FenceTime::makeValid(
+ resolvedState.state.bufferData->acquireFence),
+ "Incoming txn");
+ }
}
mBufferCountTracker.increment(resolvedState.layerId);
}
diff --git a/services/surfaceflinger/TransactionCallbackInvoker.cpp b/services/surfaceflinger/TransactionCallbackInvoker.cpp
index b22ec66..2e8c8c1 100644
--- a/services/surfaceflinger/TransactionCallbackInvoker.cpp
+++ b/services/surfaceflinger/TransactionCallbackInvoker.cpp
@@ -18,7 +18,7 @@
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
-//#define LOG_NDEBUG 0
+// #define LOG_NDEBUG 0
#undef LOG_TAG
#define LOG_TAG "TransactionCallbackInvoker"
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
@@ -28,6 +28,7 @@
#include "Utils/FenceUtils.h"
#include <binder/IInterface.h>
+#include <common/FlagManager.h>
#include <common/trace.h>
#include <utils/RefBase.h>
@@ -142,8 +143,17 @@
handle->transformHint,
handle->currentMaxAcquiredBufferCount,
eventStats, handle->previousReleaseCallbackId);
+
if (handle->bufferReleaseChannel &&
handle->previousReleaseCallbackId != ReleaseCallbackId::INVALID_ID) {
+ if (FlagManager::getInstance().monitor_buffer_fences()) {
+ if (auto previousBuffer = handle->previousBuffer.lock()) {
+ previousBuffer->getBuffer()
+ ->getDependencyMonitor()
+ .addEgress(FenceTime::makeValid(handle->previousReleaseFence),
+ "Txn release");
+ }
+ }
mBufferReleases.emplace_back(handle->name, handle->bufferReleaseChannel,
handle->previousReleaseCallbackId,
handle->previousReleaseFence,
diff --git a/services/surfaceflinger/TransactionCallbackInvoker.h b/services/surfaceflinger/TransactionCallbackInvoker.h
index 178ddbb..34f6ffc 100644
--- a/services/surfaceflinger/TransactionCallbackInvoker.h
+++ b/services/surfaceflinger/TransactionCallbackInvoker.h
@@ -25,6 +25,7 @@
#include <ftl/future.h>
#include <gui/BufferReleaseChannel.h>
#include <gui/ITransactionCompletedListener.h>
+#include <renderengine/ExternalTexture.h>
#include <ui/Fence.h>
#include <ui/FenceResult.h>
@@ -55,6 +56,7 @@
uint64_t previousFrameNumber = 0;
ReleaseCallbackId previousReleaseCallbackId = ReleaseCallbackId::INVALID_ID;
std::shared_ptr<gui::BufferReleaseChannel::ProducerEndpoint> bufferReleaseChannel;
+ std::weak_ptr<renderengine::ExternalTexture> previousBuffer;
};
class TransactionCallbackInvoker {
diff --git a/services/surfaceflinger/common/FlagManager.cpp b/services/surfaceflinger/common/FlagManager.cpp
index 5ff3d82..bf10351 100644
--- a/services/surfaceflinger/common/FlagManager.cpp
+++ b/services/surfaceflinger/common/FlagManager.cpp
@@ -129,6 +129,7 @@
DUMP_ACONFIG_FLAG(correct_virtual_display_power_state);
DUMP_ACONFIG_FLAG(graphite_renderengine_preview_rollout);
DUMP_ACONFIG_FLAG(increase_missed_frame_jank_threshold);
+ DUMP_ACONFIG_FLAG(monitor_buffer_fences);
DUMP_ACONFIG_FLAG(refresh_rate_overlay_on_external_display);
DUMP_ACONFIG_FLAG(vsync_predictor_recovery);
@@ -303,6 +304,7 @@
FLAG_MANAGER_ACONFIG_FLAG(adpf_native_session_manager, "");
FLAG_MANAGER_ACONFIG_FLAG(graphite_renderengine_preview_rollout, "");
FLAG_MANAGER_ACONFIG_FLAG(increase_missed_frame_jank_threshold, "");
+FLAG_MANAGER_ACONFIG_FLAG(monitor_buffer_fences, "");
FLAG_MANAGER_ACONFIG_FLAG(vsync_predictor_recovery, "");
/// Trunk stable server (R/W) flags from outside SurfaceFlinger ///
diff --git a/services/surfaceflinger/common/include/common/FlagManager.h b/services/surfaceflinger/common/include/common/FlagManager.h
index 419e92b..8f361ac 100644
--- a/services/surfaceflinger/common/include/common/FlagManager.h
+++ b/services/surfaceflinger/common/include/common/FlagManager.h
@@ -63,6 +63,7 @@
bool correct_virtual_display_power_state() const;
bool graphite_renderengine_preview_rollout() const;
bool increase_missed_frame_jank_threshold() const;
+ bool monitor_buffer_fences() const;
bool refresh_rate_overlay_on_external_display() const;
bool vsync_predictor_recovery() const;
diff --git a/services/surfaceflinger/surfaceflinger_flags_new.aconfig b/services/surfaceflinger/surfaceflinger_flags_new.aconfig
index d8f51fe..d412a19 100644
--- a/services/surfaceflinger/surfaceflinger_flags_new.aconfig
+++ b/services/surfaceflinger/surfaceflinger_flags_new.aconfig
@@ -216,6 +216,13 @@
} # local_tonemap_screenshots
flag {
+ name: "monitor_buffer_fences"
+ namespace: "core_graphics"
+ description: "Monitors fences for each buffer"
+ bug: "360932099"
+} # monitor_buffer_fences
+
+flag {
name: "no_vsyncs_on_screen_off"
namespace: "core_graphics"
description: "Stop vsync / Choreographer callbacks to apps when the screen is off"