egl: Avoid use of retire as present
Retire fences from HWC1 are implemented inconsitently,
so present emulation doesn't always work well.
This patch disables present for all HWC1 based devices.
Test: adb shell /data/nativetest/libgui_test/libgui_test
--gtest_filter=*GetFrameTimestamps*
Bug: 36730849, 36887025
Change-Id: I1eba2f8490c2f6feced2a36d1efc4cd66be7da40
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 5a32d05..4d2692f 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -166,6 +166,50 @@
return result != 0;
}
+ virtual status_t getSupportedFrameTimestamps(
+ std::vector<FrameEvent>* outSupported) const {
+ if (!outSupported) {
+ return UNEXPECTED_NULL;
+ }
+ outSupported->clear();
+
+ Parcel data, reply;
+
+ status_t err = data.writeInterfaceToken(
+ ISurfaceComposer::getInterfaceDescriptor());
+ if (err != NO_ERROR) {
+ return err;
+ }
+
+ err = remote()->transact(
+ BnSurfaceComposer::GET_SUPPORTED_FRAME_TIMESTAMPS,
+ data, &reply);
+ if (err != NO_ERROR) {
+ return err;
+ }
+
+ int32_t result = 0;
+ err = reply.readInt32(&result);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ if (result != NO_ERROR) {
+ return result;
+ }
+
+ std::vector<int32_t> supported;
+ err = reply.readInt32Vector(&supported);
+ if (err != NO_ERROR) {
+ return err;
+ }
+
+ outSupported->reserve(supported.size());
+ for (int32_t s : supported) {
+ outSupported->push_back(static_cast<FrameEvent>(s));
+ }
+ return NO_ERROR;
+ }
+
virtual sp<IDisplayEventConnection> createDisplayEventConnection()
{
Parcel data, reply;
@@ -536,6 +580,25 @@
reply->writeInt32(result);
return NO_ERROR;
}
+ case GET_SUPPORTED_FRAME_TIMESTAMPS: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ std::vector<FrameEvent> supportedTimestamps;
+ status_t result = getSupportedFrameTimestamps(&supportedTimestamps);
+ status_t err = reply->writeInt32(result);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ if (result != NO_ERROR) {
+ return result;
+ }
+
+ std::vector<int32_t> supported;
+ supported.reserve(supportedTimestamps.size());
+ for (FrameEvent s : supportedTimestamps) {
+ supported.push_back(static_cast<int32_t>(s));
+ }
+ return reply->writeInt32Vector(supported);
+ }
case CREATE_DISPLAY_EVENT_CONNECTION: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
sp<IDisplayEventConnection> connection(createDisplayEventConnection());
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 1149b89..41221aa 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -52,6 +52,8 @@
mAutoRefresh(false),
mSharedBufferSlot(BufferItem::INVALID_BUFFER_SLOT),
mSharedBufferHasBeenQueued(false),
+ mQueriedSupportedTimestamps(false),
+ mFrameTimestampsSupportsPresent(false),
mEnableFrameTimestamps(false),
mFrameEventHistory(std::make_unique<ProducerFrameEventHistory>())
{
@@ -209,8 +211,8 @@
bool checkForDisplayPresent = (outDisplayPresentTime != nullptr) &&
!e->hasDisplayPresentInfo();
- // LastRefreshStart, DequeueReady, and Release are never
- // available for the last frame.
+ // LastRefreshStart, DequeueReady, and Release are never available for the
+ // last frame.
bool checkForLastRefreshStart = (outLastRefreshStartTime != nullptr) &&
!e->hasLastRefreshStartInfo() &&
(e->frameNumber != lastFrameNumber);
@@ -252,6 +254,12 @@
return INVALID_OPERATION;
}
+ // Verify the requested timestamps are supported.
+ querySupportedTimestampsLocked();
+ if (outDisplayPresentTime != nullptr && !mFrameTimestampsSupportsPresent) {
+ return BAD_VALUE;
+ }
+
FrameEvents* events = mFrameEventHistory->getFrame(frameNumber);
if (events == nullptr) {
// If the entry isn't available in the producer, it's definitely not
@@ -739,6 +747,29 @@
return err;
}
+void Surface::querySupportedTimestampsLocked() const {
+ // mMutex must be locked when calling this method.
+
+ if (mQueriedSupportedTimestamps) {
+ return;
+ }
+ mQueriedSupportedTimestamps = true;
+
+ std::vector<FrameEvent> supportedFrameTimestamps;
+ status_t err = composerService()->getSupportedFrameTimestamps(
+ &supportedFrameTimestamps);
+
+ if (err != NO_ERROR) {
+ return;
+ }
+
+ for (auto sft : supportedFrameTimestamps) {
+ if (sft == FrameEvent::DISPLAY_PRESENT) {
+ mFrameTimestampsSupportsPresent = true;
+ }
+ }
+}
+
int Surface::query(int what, int* value) const {
ATRACE_CALL();
ALOGV("Surface::query");
@@ -800,6 +831,11 @@
static_cast<int>(durationUs);
return NO_ERROR;
}
+ case NATIVE_WINDOW_FRAME_TIMESTAMPS_SUPPORTS_PRESENT: {
+ querySupportedTimestampsLocked();
+ *value = mFrameTimestampsSupportsPresent ? 1 : 0;
+ return NO_ERROR;
+ }
case NATIVE_WINDOW_IS_VALID: {
*value = mGraphicBufferProducer != nullptr ? 1 : 0;
return NO_ERROR;
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index ce11486..00a374d 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -368,6 +368,10 @@
public:
~FakeSurfaceComposer() override {}
+ void setSupportsPresent(bool supportsPresent) {
+ mSupportsPresent = supportsPresent;
+ }
+
sp<ISurfaceComposerClient> createConnection() override { return nullptr; }
sp<ISurfaceComposerClient> createScopedConnection(
const sp<IGraphicBufferProducer>& /* parent */) override {
@@ -391,6 +395,26 @@
const sp<IGraphicBufferProducer>& /*surface*/) const override {
return false;
}
+
+ status_t getSupportedFrameTimestamps(std::vector<FrameEvent>* outSupported)
+ const override {
+ *outSupported = {
+ FrameEvent::REQUESTED_PRESENT,
+ FrameEvent::ACQUIRE,
+ FrameEvent::LATCH,
+ FrameEvent::FIRST_REFRESH_START,
+ FrameEvent::LAST_REFRESH_START,
+ FrameEvent::GPU_COMPOSITION_DONE,
+ FrameEvent::DEQUEUE_READY,
+ FrameEvent::RELEASE
+ };
+ if (mSupportsPresent) {
+ outSupported->push_back(
+ FrameEvent::DISPLAY_PRESENT);
+ }
+ return NO_ERROR;
+ }
+
void setPowerMode(const sp<IBinder>& /*display*/, int /*mode*/) override {}
status_t getDisplayConfigs(const sp<IBinder>& /*display*/,
Vector<DisplayInfo>* /*configs*/) override { return NO_ERROR; }
@@ -435,7 +459,6 @@
private:
bool mSupportsPresent{true};
- bool mSupportsRetire{true};
};
class FakeProducerFrameEventHistory : public ProducerFrameEventHistory {
@@ -864,6 +887,28 @@
EXPECT_EQ(4, mFakeConsumer->mGetFrameTimestampsCount);
}
+TEST_F(GetFrameTimestampsTest, QueryPresentSupported) {
+ bool displayPresentSupported = true;
+ mSurface->mFakeSurfaceComposer->setSupportsPresent(displayPresentSupported);
+
+ // Verify supported bits are forwarded.
+ int supportsPresent = -1;
+ mWindow.get()->query(mWindow.get(),
+ NATIVE_WINDOW_FRAME_TIMESTAMPS_SUPPORTS_PRESENT, &supportsPresent);
+ EXPECT_EQ(displayPresentSupported, supportsPresent);
+}
+
+TEST_F(GetFrameTimestampsTest, QueryPresentNotSupported) {
+ bool displayPresentSupported = false;
+ mSurface->mFakeSurfaceComposer->setSupportsPresent(displayPresentSupported);
+
+ // Verify supported bits are forwarded.
+ int supportsPresent = -1;
+ mWindow.get()->query(mWindow.get(),
+ NATIVE_WINDOW_FRAME_TIMESTAMPS_SUPPORTS_PRESENT, &supportsPresent);
+ EXPECT_EQ(displayPresentSupported, supportsPresent);
+}
+
TEST_F(GetFrameTimestampsTest, SnapToNextTickBasic) {
nsecs_t phase = 4000;
nsecs_t interval = 1000;
@@ -1228,8 +1273,8 @@
// Verify a request for no timestamps doesn't result in a sync call.
int oldCount = mFakeConsumer->mGetFrameTimestampsCount;
int result = native_window_get_frame_timestamps(mWindow.get(), fId2,
- nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
- nullptr, nullptr, nullptr);
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr);
EXPECT_EQ(NO_ERROR, result);
EXPECT_EQ(oldCount, mFakeConsumer->mGetFrameTimestampsCount);
}
@@ -1371,7 +1416,7 @@
// This test verifies that if the certain timestamps can't possibly exist for
// the most recent frame, then a sync call is not done.
-TEST_F(GetFrameTimestampsTest, NoRetireOrReleaseNoSync) {
+TEST_F(GetFrameTimestampsTest, NoReleaseNoSync) {
enableFrameTimestamps();
// Dequeue and queue frame 1.
@@ -1431,4 +1476,27 @@
EXPECT_EQ(0, outReleaseTime);
}
+// This test verifies there are no sync calls for present times
+// when they aren't supported and that an error is returned.
+
+TEST_F(GetFrameTimestampsTest, PresentUnsupportedNoSync) {
+ enableFrameTimestamps();
+ mSurface->mFakeSurfaceComposer->setSupportsPresent(false);
+
+ // Dequeue and queue frame 1.
+ const uint64_t fId1 = getNextFrameId();
+ dequeueAndQueue(0);
+
+ // Verify a query for the Present times do not trigger a sync call if they
+ // are not supported.
+ resetTimestamps();
+ int oldCount = mFakeConsumer->mGetFrameTimestampsCount;
+ int result = native_window_get_frame_timestamps(mWindow.get(), fId1,
+ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+ &outDisplayPresentTime, nullptr, nullptr);
+ EXPECT_EQ(oldCount, mFakeConsumer->mGetFrameTimestampsCount);
+ EXPECT_EQ(BAD_VALUE, result);
+ EXPECT_EQ(-1, outDisplayPresentTime);
+}
+
}
diff --git a/libs/hwc2on1adapter/HWC2On1Adapter.cpp b/libs/hwc2on1adapter/HWC2On1Adapter.cpp
index e35bfc9..8c6ef69 100644
--- a/libs/hwc2on1adapter/HWC2On1Adapter.cpp
+++ b/libs/hwc2on1adapter/HWC2On1Adapter.cpp
@@ -2246,6 +2246,11 @@
mHwc1SupportsBackgroundColor = true;
}
}
+
+ // Some devices might have HWC1 retire fences that accurately emulate
+ // HWC2 present fences when they are deferred, but it's not very reliable.
+ // To be safe, we indicate PresentFenceIsNotReliable for all HWC1 devices.
+ mCapabilities.insert(Capability::PresentFenceIsNotReliable);
}
HWC2On1Adapter::Display* HWC2On1Adapter::getDisplay(hwc2_display_t id) {
diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h
index 63d1ad1..0251aed 100644
--- a/libs/nativewindow/include/system/window.h
+++ b/libs/nativewindow/include/system/window.h
@@ -186,6 +186,12 @@
* if it is safe (i.e. no crash will occur) to call any method on it.
*/
NATIVE_WINDOW_IS_VALID = 17,
+
+ /*
+ * Returns 1 if NATIVE_WINDOW_GET_FRAME_TIMESTAMPS will return display
+ * present info, 0 if it won't.
+ */
+ NATIVE_WINDOW_FRAME_TIMESTAMPS_SUPPORTS_PRESENT = 18,
};
/* Valid operations for the (*perform)() hook.