egl: Differentiate pending vs invalid timestamps.
Test: adb shell /data/nativetest/libgui_test/libgui_test
--gtest_filter=*GetFrameTimestamps*
Change-Id: Iaa418ff1753a4339bfefaa68a6b03e8c96366a87
diff --git a/include/gui/FrameTimestamps.h b/include/gui/FrameTimestamps.h
index 92251ed..9716be4 100644
--- a/include/gui/FrameTimestamps.h
+++ b/include/gui/FrameTimestamps.h
@@ -54,8 +54,7 @@
static constexpr auto EVENT_COUNT =
static_cast<size_t>(FrameEvent::EVENT_COUNT);
static_assert(EVENT_COUNT <= 32, "Event count sanity check failed.");
- static constexpr nsecs_t TIMESTAMP_PENDING =
- std::numeric_limits<nsecs_t>::max();
+ static constexpr nsecs_t TIMESTAMP_PENDING = -2;
static inline bool isValidTimestamp(nsecs_t time) {
return time != TIMESTAMP_PENDING;
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 41221aa..a6d9e66 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -229,14 +229,26 @@
static void getFrameTimestamp(nsecs_t *dst, const nsecs_t& src) {
if (dst != nullptr) {
- *dst = FrameEvents::isValidTimestamp(src) ? src : 0;
+ // We always get valid timestamps for these eventually.
+ *dst = (src == FrameEvents::TIMESTAMP_PENDING) ?
+ NATIVE_WINDOW_TIMESTAMP_PENDING : src;
}
}
-static void getFrameTimestampFence(nsecs_t *dst, const std::shared_ptr<FenceTime>& src) {
+static void getFrameTimestampFence(nsecs_t *dst,
+ const std::shared_ptr<FenceTime>& src, bool fenceShouldBeKnown) {
if (dst != nullptr) {
+ if (!fenceShouldBeKnown) {
+ *dst = NATIVE_WINDOW_TIMESTAMP_PENDING;
+ return;
+ }
+
nsecs_t signalTime = src->getSignalTime();
- *dst = Fence::isValidTimestamp(signalTime) ? signalTime : 0;
+ *dst = (signalTime == Fence::SIGNAL_TIME_PENDING) ?
+ NATIVE_WINDOW_TIMESTAMP_PENDING :
+ (signalTime == Fence::SIGNAL_TIME_INVALID) ?
+ NATIVE_WINDOW_TIMESTAMP_INVALID :
+ signalTime;
}
}
@@ -290,12 +302,15 @@
getFrameTimestamp(outLastRefreshStartTime, events->lastRefreshStartTime);
getFrameTimestamp(outDequeueReadyTime, events->dequeueReadyTime);
- getFrameTimestampFence(outAcquireTime, events->acquireFence);
- getFrameTimestampFence(
- outGpuCompositionDoneTime, events->gpuCompositionDoneFence);
- getFrameTimestampFence(
- outDisplayPresentTime, events->displayPresentFence);
- getFrameTimestampFence(outReleaseTime, events->releaseFence);
+ getFrameTimestampFence(outAcquireTime, events->acquireFence,
+ events->hasAcquireInfo());
+ getFrameTimestampFence(outGpuCompositionDoneTime,
+ events->gpuCompositionDoneFence,
+ events->hasGpuCompositionDoneInfo());
+ getFrameTimestampFence(outDisplayPresentTime, events->displayPresentFence,
+ events->hasDisplayPresentInfo());
+ getFrameTimestampFence(outReleaseTime, events->releaseFence,
+ events->hasReleaseInfo());
return NO_ERROR;
}
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 00a374d..cf3d1b2 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -1184,8 +1184,8 @@
EXPECT_EQ(mFrames[1].mRefreshes[0].kGpuCompositionDoneTime,
outGpuCompositionDoneTime);
EXPECT_EQ(mFrames[1].mRefreshes[0].kPresentTime, outDisplayPresentTime);
- EXPECT_EQ(0, outDequeueReadyTime);
- EXPECT_EQ(0, outReleaseTime);
+ EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_PENDING, outDequeueReadyTime);
+ EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_PENDING, outReleaseTime);
}
// This test verifies the acquire fence recorded by the consumer is not sent
@@ -1208,7 +1208,7 @@
EXPECT_EQ(oldCount, mFakeConsumer->mGetFrameTimestampsCount);
EXPECT_EQ(NO_ERROR, result);
EXPECT_EQ(mFrames[0].kRequestedPresentTime, outRequestedPresentTime);
- EXPECT_EQ(0, outAcquireTime);
+ EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_PENDING, outAcquireTime);
// Signal acquire fences. Verify a sync call still isn't necessary.
mFrames[0].signalQueueFences();
@@ -1237,7 +1237,7 @@
EXPECT_EQ(oldCount, mFakeConsumer->mGetFrameTimestampsCount);
EXPECT_EQ(NO_ERROR, result);
EXPECT_EQ(mFrames[1].kRequestedPresentTime, outRequestedPresentTime);
- EXPECT_EQ(0, outAcquireTime);
+ EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_PENDING, outAcquireTime);
// Signal acquire fences. Verify a sync call still isn't necessary.
mFrames[1].signalQueueFences();
@@ -1310,10 +1310,10 @@
EXPECT_EQ(mFrames[0].kLatchTime, outLatchTime);
EXPECT_EQ(mFrames[0].mRefreshes[0].kStartTime, outFirstRefreshStartTime);
EXPECT_EQ(mFrames[0].mRefreshes[2].kStartTime, outLastRefreshStartTime);
- EXPECT_EQ(0, outGpuCompositionDoneTime);
- EXPECT_EQ(0, outDisplayPresentTime);
+ EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_PENDING, outGpuCompositionDoneTime);
+ EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_PENDING, outDisplayPresentTime);
EXPECT_EQ(mFrames[0].kDequeueReadyTime, outDequeueReadyTime);
- EXPECT_EQ(0, outReleaseTime);
+ EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_PENDING, outReleaseTime);
// Verify available timestamps are correct for frame 1 again, before any
// fence has been signaled.
@@ -1328,10 +1328,10 @@
EXPECT_EQ(mFrames[0].kLatchTime, outLatchTime);
EXPECT_EQ(mFrames[0].mRefreshes[0].kStartTime, outFirstRefreshStartTime);
EXPECT_EQ(mFrames[0].mRefreshes[2].kStartTime, outLastRefreshStartTime);
- EXPECT_EQ(0, outGpuCompositionDoneTime);
- EXPECT_EQ(0, outDisplayPresentTime);
+ EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_PENDING, outGpuCompositionDoneTime);
+ EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_PENDING, outDisplayPresentTime);
EXPECT_EQ(mFrames[0].kDequeueReadyTime, outDequeueReadyTime);
- EXPECT_EQ(0, outReleaseTime);
+ EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_PENDING, outReleaseTime);
// Signal the fences for frame 1.
mFrames[0].signalRefreshFences();
@@ -1387,10 +1387,10 @@
EXPECT_EQ(mFrames[0].kLatchTime, outLatchTime);
EXPECT_EQ(mFrames[0].mRefreshes[0].kStartTime, outFirstRefreshStartTime);
EXPECT_EQ(mFrames[0].mRefreshes[2].kStartTime, outLastRefreshStartTime);
- EXPECT_EQ(0, outGpuCompositionDoneTime);
- EXPECT_EQ(0, outDisplayPresentTime);
+ EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_INVALID, outGpuCompositionDoneTime);
+ EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_PENDING, outDisplayPresentTime);
EXPECT_EQ(mFrames[0].kDequeueReadyTime, outDequeueReadyTime);
- EXPECT_EQ(0, outReleaseTime);
+ EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_PENDING, outReleaseTime);
// Signal the fences for frame 1.
mFrames[0].signalRefreshFences();
@@ -1408,7 +1408,7 @@
EXPECT_EQ(mFrames[0].kLatchTime, outLatchTime);
EXPECT_EQ(mFrames[0].mRefreshes[0].kStartTime, outFirstRefreshStartTime);
EXPECT_EQ(mFrames[0].mRefreshes[2].kStartTime, outLastRefreshStartTime);
- EXPECT_EQ(0, outGpuCompositionDoneTime);
+ EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_INVALID, outGpuCompositionDoneTime);
EXPECT_EQ(mFrames[0].mRefreshes[0].kPresentTime, outDisplayPresentTime);
EXPECT_EQ(mFrames[0].kDequeueReadyTime, outDequeueReadyTime);
EXPECT_EQ(mFrames[0].kReleaseTime, outReleaseTime);
@@ -1446,10 +1446,10 @@
EXPECT_EQ(mFrames[0].kLatchTime, outLatchTime);
EXPECT_EQ(mFrames[0].mRefreshes[0].kStartTime, outFirstRefreshStartTime);
EXPECT_EQ(mFrames[0].mRefreshes[2].kStartTime, outLastRefreshStartTime);
- EXPECT_EQ(0, outGpuCompositionDoneTime);
- EXPECT_EQ(0, outDisplayPresentTime);
+ EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_INVALID, outGpuCompositionDoneTime);
+ EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_PENDING, outDisplayPresentTime);
EXPECT_EQ(mFrames[0].kDequeueReadyTime, outDequeueReadyTime);
- EXPECT_EQ(0, outReleaseTime);
+ EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_PENDING, outReleaseTime);
mFrames[0].signalRefreshFences();
mFrames[0].signalReleaseFences();
@@ -1470,10 +1470,10 @@
EXPECT_EQ(mFrames[1].kLatchTime, outLatchTime);
EXPECT_EQ(mFrames[1].mRefreshes[0].kStartTime, outFirstRefreshStartTime);
EXPECT_EQ(mFrames[1].mRefreshes[1].kStartTime, outLastRefreshStartTime);
- EXPECT_EQ(0, outGpuCompositionDoneTime);
+ EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_INVALID, outGpuCompositionDoneTime);
EXPECT_EQ(mFrames[1].mRefreshes[0].kPresentTime, outDisplayPresentTime);
- EXPECT_EQ(0, outDequeueReadyTime);
- EXPECT_EQ(0, outReleaseTime);
+ EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_PENDING, outDequeueReadyTime);
+ EXPECT_EQ(NATIVE_WINDOW_TIMESTAMP_PENDING, outReleaseTime);
}
// This test verifies there are no sync calls for present times
diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h
index 0251aed..fb67a51 100644
--- a/libs/nativewindow/include/system/window.h
+++ b/libs/nativewindow/include/system/window.h
@@ -311,6 +311,14 @@
*/
static const int64_t NATIVE_WINDOW_TIMESTAMP_AUTO = (-9223372036854775807LL-1);
+/* parameter for NATIVE_WINDOW_GET_FRAME_TIMESTAMPS
+ *
+ * Special timestamp value to indicate the timestamps aren't yet known or
+ * that they are invalid.
+ */
+static const int64_t NATIVE_WINDOW_TIMESTAMP_PENDING = -2;
+static const int64_t NATIVE_WINDOW_TIMESTAMP_INVALID = -1;
+
struct ANativeWindow
{
#ifdef __cplusplus
diff --git a/opengl/include/EGL/eglext.h b/opengl/include/EGL/eglext.h
index bf831a7..3068029 100644
--- a/opengl/include/EGL/eglext.h
+++ b/opengl/include/EGL/eglext.h
@@ -640,6 +640,8 @@
#define EGL_DISPLAY_PRESENT_TIME_ANDROID 0x3157
#define EGL_DEQUEUE_READY_TIME_ANDROID 0x3158
#define EGL_READS_DONE_TIME_ANDROID 0x3159
+#define EGL_TIMESTAMP_PENDING_ANDROID EGL_CAST(EGLnsecsANDROID, -2)
+#define EGL_TIMESTAMP_INVALID_ANDROID EGL_CAST(EGLnsecsANDROID, -1)
#ifdef EGL_EGLEXT_PROTOTYPES
EGLAPI EGLBoolean eglGetNextFrameIdANDROID(EGLDisplay dpy, EGLSurface surface, EGLuint64KHR *frameId);
EGLAPI EGLBoolean eglGetCompositorTimingANDROID(EGLDisplay dpy, EGLSurface surface, EGLint numTimestamps, const EGLint *names, EGLnsecsANDROID *values);
diff --git a/opengl/specs/EGL_ANDROID_get_frame_timestamps.txt b/opengl/specs/EGL_ANDROID_get_frame_timestamps.txt
index 61b9b66..03b8954 100644
--- a/opengl/specs/EGL_ANDROID_get_frame_timestamps.txt
+++ b/opengl/specs/EGL_ANDROID_get_frame_timestamps.txt
@@ -94,6 +94,8 @@
EGL_DISPLAY_PRESENT_TIME_ANDROID 0x3157
EGL_DEQUEUE_READY_TIME_ANDROID 0x3158
EGL_READS_DONE_TIME_ANDROID 0x3159
+ EGL_TIMESTAMP_PENDING_ANDROID -2
+ EGL_TIMESTAMP_INVALID_ANDROID -1
Add to the list of supported tokens for eglSurfaceAttrib in section 3.5.6
"Surface Attributes", page 43:
@@ -155,10 +157,12 @@
limited history of timestamp data. If a query is made for a frame whose
timestamp history no longer exists then EGL_BAD_ACCESS is generated. If
timestamp collection has not been enabled for the surface then
- EGL_BAD_SURFACE is generated. Timestamps for events that will not occur or
- have not yet occurred will be zero. Timestamp queries that are not
- supported will generate an EGL_BAD_PARAMETER error. If any error is
- generated the function will return EGL_FALSE.
+ EGL_BAD_SURFACE is generated. Timestamps for events that might still occur
+ will have the value EGL_TIMESTAMP_PENDING_ANDROID. Timestamps for events
+ that did not occur will have the value EGL_TIMESTAMP_INVALID_ANDROID.
+ Otherwise, the timestamp will be valid and indicate the event has occured.
+ Timestamp queries that are not supported will generate an EGL_BAD_PARAMETER
+ error. If any error is generated the function will return EGL_FALSE.
The application can poll for the timestamp of particular events by calling
eglGetFrameTimestamps over and over without needing to call any other EGL
@@ -222,6 +226,9 @@
Revision History
+#7 (Brian Anderson, March 21, 2017)
+ - Differentiate between pending events and events that did not occur.
+
#6 (Brian Anderson, March 16, 2017)
- Remove DISPLAY_RETIRE_TIME_ANDROID.
diff --git a/vulkan/libvulkan/Android.bp b/vulkan/libvulkan/Android.bp
index 9444da5..a35fb98 100644
--- a/vulkan/libvulkan/Android.bp
+++ b/vulkan/libvulkan/Android.bp
@@ -78,6 +78,7 @@
"libutils",
"libcutils",
"libz",
+ "libnativewindow",
],
static_libs: ["libgrallocusage"],
}
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 3b785e6..caa2674 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -114,14 +114,34 @@
: vals_{qp->presentID, qp->desiredPresentTime, 0, 0, 0},
native_frame_id_(nativeFrameId) {}
bool ready() const {
- return (timestamp_desired_present_time_ &&
- timestamp_actual_present_time_ &&
- timestamp_render_complete_time_ &&
- timestamp_composition_latch_time_);
+ return (timestamp_desired_present_time_ !=
+ NATIVE_WINDOW_TIMESTAMP_PENDING &&
+ timestamp_actual_present_time_ !=
+ NATIVE_WINDOW_TIMESTAMP_PENDING &&
+ timestamp_render_complete_time_ !=
+ NATIVE_WINDOW_TIMESTAMP_PENDING &&
+ timestamp_composition_latch_time_ !=
+ NATIVE_WINDOW_TIMESTAMP_PENDING);
}
- void calculate(uint64_t rdur) {
- vals_.actualPresentTime = timestamp_actual_present_time_;
- uint64_t margin = (timestamp_composition_latch_time_ -
+ void calculate(int64_t rdur) {
+ bool anyTimestampInvalid =
+ (timestamp_actual_present_time_ ==
+ NATIVE_WINDOW_TIMESTAMP_INVALID) ||
+ (timestamp_render_complete_time_ ==
+ NATIVE_WINDOW_TIMESTAMP_INVALID) ||
+ (timestamp_composition_latch_time_ ==
+ NATIVE_WINDOW_TIMESTAMP_INVALID);
+ if (anyTimestampInvalid) {
+ ALOGE("Unexpectedly received invalid timestamp.");
+ vals_.actualPresentTime = 0;
+ vals_.earliestPresentTime = 0;
+ vals_.presentMargin = 0;
+ return;
+ }
+
+ vals_.actualPresentTime =
+ static_cast<uint64_t>(timestamp_actual_present_time_);
+ int64_t margin = (timestamp_composition_latch_time_ -
timestamp_render_complete_time_);
// Calculate vals_.earliestPresentTime, and potentially adjust
// vals_.presentMargin. The initial value of vals_.earliestPresentTime
@@ -132,14 +152,14 @@
// it did (per the extension specification). If for some reason, we
// can do this subtraction repeatedly, we do, since
// vals_.earliestPresentTime really is supposed to be the "earliest".
- uint64_t early_time = vals_.actualPresentTime;
+ int64_t early_time = timestamp_actual_present_time_;
while ((margin > rdur) &&
((early_time - rdur) > timestamp_composition_latch_time_)) {
early_time -= rdur;
margin -= rdur;
}
- vals_.earliestPresentTime = early_time;
- vals_.presentMargin = margin;
+ vals_.earliestPresentTime = static_cast<uint64_t>(early_time);
+ vals_.presentMargin = static_cast<uint64_t>(margin);
}
void get_values(VkPastPresentationTimingGOOGLE* values) const {
*values = vals_;
@@ -149,10 +169,11 @@
VkPastPresentationTimingGOOGLE vals_ { 0, 0, 0, 0, 0 };
uint64_t native_frame_id_ { 0 };
- uint64_t timestamp_desired_present_time_ { 0 };
- uint64_t timestamp_actual_present_time_ { 0 };
- uint64_t timestamp_render_complete_time_ { 0 };
- uint64_t timestamp_composition_latch_time_ { 0 };
+ int64_t timestamp_desired_present_time_{ NATIVE_WINDOW_TIMESTAMP_PENDING };
+ int64_t timestamp_actual_present_time_ { NATIVE_WINDOW_TIMESTAMP_PENDING };
+ int64_t timestamp_render_complete_time_ { NATIVE_WINDOW_TIMESTAMP_PENDING };
+ int64_t timestamp_composition_latch_time_
+ { NATIVE_WINDOW_TIMESTAMP_PENDING };
};
// ----------------------------------------------------------------------------
@@ -187,18 +208,16 @@
shared(present_mode == VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR ||
present_mode == VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR) {
ANativeWindow* window = surface.window.get();
- int64_t rdur;
native_window_get_refresh_cycle_duration(
window,
- &rdur);
- refresh_duration = static_cast<uint64_t>(rdur);
+ &refresh_duration);
}
Surface& surface;
uint32_t num_images;
bool mailbox_mode;
bool frame_timestamps_enabled;
- uint64_t refresh_duration;
+ int64_t refresh_duration;
bool shared;
struct Image {
@@ -327,14 +346,10 @@
// Record the timestamp(s) we received, and then see if this TimingInfo
// is ready to be reported to the user:
- ti.timestamp_desired_present_time_ =
- static_cast<uint64_t>(desired_present_time);
- ti.timestamp_actual_present_time_ =
- static_cast<uint64_t>(actual_present_time);
- ti.timestamp_render_complete_time_ =
- static_cast<uint64_t>(render_complete_time);
- ti.timestamp_composition_latch_time_ =
- static_cast<uint64_t>(composition_latch_time);
+ ti.timestamp_desired_present_time_ = desired_present_time;
+ ti.timestamp_actual_present_time_ = actual_present_time;
+ ti.timestamp_render_complete_time_ = render_complete_time;
+ ti.timestamp_composition_latch_time_ = composition_latch_time;
if (ti.ready()) {
// The TimingInfo has received enough timestamps, and should now
@@ -1494,7 +1509,8 @@
Swapchain& swapchain = *SwapchainFromHandle(swapchain_handle);
VkResult result = VK_SUCCESS;
- pDisplayTimingProperties->refreshDuration = swapchain.refresh_duration;
+ pDisplayTimingProperties->refreshDuration =
+ static_cast<uint64_t>(swapchain.refresh_duration);
return result;
}