diff options
| author | 2017-03-20 16:54:25 -0700 | |
|---|---|---|
| committer | 2017-04-11 16:57:11 -0700 | |
| commit | dc96fdfa58260867c993fff78611220874753201 (patch) | |
| tree | debb2fb42d1c93fb6f86d6441023a7148715dcea | |
| parent | 6b376713907086c9642e7b7e66e51ddfa531b003 (diff) | |
egl: Differentiate pending vs invalid timestamps.
Test: adb shell /data/nativetest/libgui_test/libgui_test
--gtest_filter=*GetFrameTimestamps*
Change-Id: Iaa418ff1753a4339bfefaa68a6b03e8c96366a87
| -rw-r--r-- | include/gui/FrameTimestamps.h | 3 | ||||
| -rw-r--r-- | libs/gui/Surface.cpp | 33 | ||||
| -rw-r--r-- | libs/gui/tests/Surface_test.cpp | 40 | ||||
| -rw-r--r-- | libs/nativewindow/include/system/window.h | 8 | ||||
| -rw-r--r-- | opengl/include/EGL/eglext.h | 2 | ||||
| -rw-r--r-- | opengl/specs/EGL_ANDROID_get_frame_timestamps.txt | 15 | ||||
| -rw-r--r-- | vulkan/libvulkan/Android.bp | 1 | ||||
| -rw-r--r-- | vulkan/libvulkan/swapchain.cpp | 70 |
8 files changed, 110 insertions, 62 deletions
diff --git a/include/gui/FrameTimestamps.h b/include/gui/FrameTimestamps.h index 92251edca6..9716be4bfd 100644 --- a/include/gui/FrameTimestamps.h +++ b/include/gui/FrameTimestamps.h @@ -54,8 +54,7 @@ struct FrameEvents { 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 41221aab8d..a6d9e66828 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -229,14 +229,26 @@ static bool checkConsumerForUpdates( 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 @@ status_t Surface::getFrameTimestamps(uint64_t frameNumber, 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 00a374d273..cf3d1b27c7 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -1184,8 +1184,8 @@ TEST_F(GetFrameTimestampsTest, TimestampsAssociatedWithCorrectFrame) { 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 @@ TEST_F(GetFrameTimestampsTest, QueueTimestampsNoSync) { 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 @@ TEST_F(GetFrameTimestampsTest, QueueTimestampsNoSync) { 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 @@ TEST_F(GetFrameTimestampsTest, FencesInProducerNoSync) { 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 @@ TEST_F(GetFrameTimestampsTest, FencesInProducerNoSync) { 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 @@ TEST_F(GetFrameTimestampsTest, NoGpuNoSync) { 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 @@ TEST_F(GetFrameTimestampsTest, NoGpuNoSync) { 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 @@ TEST_F(GetFrameTimestampsTest, NoReleaseNoSync) { 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 @@ TEST_F(GetFrameTimestampsTest, NoReleaseNoSync) { 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 0251aedeac..fb67a5169c 100644 --- a/libs/nativewindow/include/system/window.h +++ b/libs/nativewindow/include/system/window.h @@ -311,6 +311,14 @@ enum { */ 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 bf831a7c7a..3068029386 100644 --- a/opengl/include/EGL/eglext.h +++ b/opengl/include/EGL/eglext.h @@ -640,6 +640,8 @@ typedef EGLClientBuffer (EGLAPIENTRYP PFNEGLGETNATIVECLIENTBUFFERANDROID) (const #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 61b9b661e8..03b895435c 100644 --- a/opengl/specs/EGL_ANDROID_get_frame_timestamps.txt +++ b/opengl/specs/EGL_ANDROID_get_frame_timestamps.txt @@ -94,6 +94,8 @@ New Tokens 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 @@ Changes to Chapter 3 of the EGL 1.5 Specification (EGL Functions and Errors) 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 @@ Issues 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 9444da5f26..a35fb989ab 100644 --- a/vulkan/libvulkan/Android.bp +++ b/vulkan/libvulkan/Android.bp @@ -78,6 +78,7 @@ cc_library_shared { "libutils", "libcutils", "libz", + "libnativewindow", ], static_libs: ["libgrallocusage"], } diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp index 3b785e671d..caa2674d7b 100644 --- a/vulkan/libvulkan/swapchain.cpp +++ b/vulkan/libvulkan/swapchain.cpp @@ -114,14 +114,34 @@ class TimingInfo { : 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 @@ class TimingInfo { // 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 @@ class TimingInfo { 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 @@ struct Swapchain { 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 @@ uint32_t get_num_ready_timings(Swapchain& swapchain) { // 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 @@ VkResult GetRefreshCycleDurationGOOGLE( 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; } |