diff options
| author | Siarhei Vishniakou <svv@google.com> | 2020-11-30 10:30:52 -1000 |
|---|---|---|
| committer | Siarhei Vishniakou <svv@google.com> | 2020-12-01 15:07:50 -1000 |
| commit | efed16630a8cf71287f04cde5dc59c4e0db1d987 (patch) | |
| tree | 7d9c798140281a901d8e6ab0607b594fe48e394b /core/java/android/view | |
| parent | 26ca287da728d88709f7523113637104fb31bf3e (diff) | |
Track per-window information in ViewFrameInfo
FrameInfo will now be per-window; that is, per-ViewRootImpl.
Some of the information should remain “global” (it remain in Choreographer),
while some information is going to become ViewRootImpl-specific.
Before the information gets passed to the native layer,
the ViewRootImpl-specific info will be stitched together
with the general Choreographer info.
This change is useful in order to correctly correlate frames with a specific
input event. In the unlikely scenario of a user touching two windows of the
same app simultaneously, this change will allow us to correctly measure the
latency of both frames produced by the windows.
Design doc: https://docs.google.com/document/d/1KMpMBlOxnl7zkWBCbXZZE6ZlaHEA4efYnN6WYK8n3FE/edit?resourcekey=0-eqooVNP0SskupljlTFvtOQ
Test: atest ViewFrameInfoTest
Bug: 169866723
Change-Id: Ib0bf9cd51cbcc0b9b70460c929c480eb490ec322
Diffstat (limited to 'core/java/android/view')
| -rw-r--r-- | core/java/android/view/ThreadedRenderer.java | 8 | ||||
| -rw-r--r-- | core/java/android/view/ViewFrameInfo.java | 81 | ||||
| -rw-r--r-- | core/java/android/view/ViewRootImpl.java | 24 |
3 files changed, 107 insertions, 6 deletions
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java index 57ca71ae4b02..d839e3532b64 100644 --- a/core/java/android/view/ThreadedRenderer.java +++ b/core/java/android/view/ThreadedRenderer.java @@ -21,6 +21,7 @@ import android.annotation.Nullable; import android.app.ActivityManager; import android.content.Context; import android.content.res.TypedArray; +import android.graphics.FrameInfo; import android.graphics.HardwareRenderer; import android.graphics.Picture; import android.graphics.Point; @@ -610,8 +611,7 @@ public final class ThreadedRenderer extends HardwareRenderer { * @param attachInfo AttachInfo tied to the specified view. */ void draw(View view, AttachInfo attachInfo, DrawCallbacks callbacks) { - final Choreographer choreographer = attachInfo.mViewRootImpl.mChoreographer; - choreographer.mFrameInfo.markDrawStart(); + attachInfo.mViewRootImpl.mViewFrameInfo.markDrawStart(); updateRootDisplayList(view, callbacks); @@ -629,7 +629,9 @@ public final class ThreadedRenderer extends HardwareRenderer { attachInfo.mPendingAnimatingRenderNodes = null; } - int syncResult = syncAndDrawFrame(choreographer.mFrameInfo); + final FrameInfo frameInfo = attachInfo.mViewRootImpl.getUpdatedFrameInfo(); + + int syncResult = syncAndDrawFrame(frameInfo); if ((syncResult & SYNC_LOST_SURFACE_REWARD_IF_FOUND) != 0) { Log.w("OpenGLRenderer", "Surface lost, forcing relayout"); // We lost our surface. For a relayout next frame which should give us a new diff --git a/core/java/android/view/ViewFrameInfo.java b/core/java/android/view/ViewFrameInfo.java new file mode 100644 index 000000000000..890d071f8090 --- /dev/null +++ b/core/java/android/view/ViewFrameInfo.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view; + +import android.graphics.FrameInfo; + +/** + * The timing information of events taking place in ViewRootImpl + * @hide + */ +public class ViewFrameInfo { + public long drawStart; + public long oldestInputEventTime; // the time of the oldest input event consumed for this frame + public long newestInputEventTime; // the time of the newest input event consumed for this frame + // Various flags set to provide extra metadata about the current frame. See flag definitions + // inside FrameInfo. + // @see android.graphics.FrameInfo.FLAG_WINDOW_LAYOUT_CHANGED + public long flags; + + /** + * Update the oldest event time. + * @param eventTime the time of the input event + */ + public void updateOldestInputEvent(long eventTime) { + if (oldestInputEventTime == 0 || eventTime < oldestInputEventTime) { + oldestInputEventTime = eventTime; + } + } + + /** + * Update the newest event time. + * @param eventTime the time of the input event + */ + public void updateNewestInputEvent(long eventTime) { + if (newestInputEventTime == 0 || eventTime > newestInputEventTime) { + newestInputEventTime = eventTime; + } + } + + /** + * Populate the missing fields using the data from ViewFrameInfo + * @param frameInfo : the structure FrameInfo object to populate + */ + public void populateFrameInfo(FrameInfo frameInfo) { + frameInfo.frameInfo[FrameInfo.FLAGS] |= flags; + frameInfo.frameInfo[FrameInfo.DRAW_START] = drawStart; + frameInfo.frameInfo[FrameInfo.OLDEST_INPUT_EVENT] = oldestInputEventTime; + frameInfo.frameInfo[FrameInfo.NEWEST_INPUT_EVENT] = newestInputEventTime; + } + + /** + * Reset this data. Should typically be invoked after calling "populateFrameInfo". + */ + public void reset() { + drawStart = 0; + oldestInputEventTime = 0; + newestInputEventTime = 0; + flags = 0; + } + + /** + * Record the current time, and store it in 'drawStart' + */ + public void markDrawStart() { + drawStart = System.nanoTime(); + } +} diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 2bea0d6b4b04..ae162ede2c70 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -423,7 +423,7 @@ public final class ViewRootImpl implements ViewParent, @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) int mHeight; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - Rect mDirty; + private Rect mDirty; public boolean mIsAnimating; private boolean mUseMTRenderer; @@ -446,6 +446,23 @@ public final class ViewRootImpl implements ViewParent, @UnsupportedAppUsage FallbackEventHandler mFallbackEventHandler; final Choreographer mChoreographer; + protected final ViewFrameInfo mViewFrameInfo = new ViewFrameInfo(); + + /** + * Update the Choreographer's FrameInfo object with the timing information for the current + * ViewRootImpl instance. Erase the data in the current ViewFrameInfo to prepare for the next + * frame. + * @return the updated FrameInfo object + */ + protected @NonNull FrameInfo getUpdatedFrameInfo() { + // Since Choreographer is a thread-local singleton while we can have multiple + // ViewRootImpl's, populate the frame information from the current viewRootImpl before + // starting the draw + FrameInfo frameInfo = mChoreographer.mFrameInfo; + mViewFrameInfo.populateFrameInfo(frameInfo); + mViewFrameInfo.reset(); + return frameInfo; + } // used in relayout to get SurfaceControl size // for BLAST adapter surface setup @@ -2675,7 +2692,7 @@ public final class ViewRootImpl implements ViewParent, // to resume them mDirty.set(0, 0, mWidth, mHeight); } - mChoreographer.mFrameInfo.addFlags(FrameInfo.FLAG_WINDOW_LAYOUT_CHANGED); + mViewFrameInfo.flags |= FrameInfo.FLAG_WINDOW_LAYOUT_CHANGED; } relayoutResult = relayoutWindow(params, viewVisibility, insetsPending); @@ -8138,7 +8155,8 @@ public final class ViewRootImpl implements ViewParent, oldestEventTime = me.getHistoricalEventTimeNano(0); } } - mChoreographer.mFrameInfo.updateInputEventTime(eventTime, oldestEventTime); + mViewFrameInfo.updateOldestInputEvent(oldestEventTime); + mViewFrameInfo.updateNewestInputEvent(eventTime); deliverInputEvent(q); } |
