diff options
author | 2014-05-02 16:46:41 -0700 | |
---|---|---|
committer | 2014-05-05 10:57:04 -0700 | |
commit | 18f16e6fba74eda173e1e7c869e6e2e2acc073ff (patch) | |
tree | d1ed13d4ea22a86109a09c309efb7e3d9c79112c | |
parent | 29e594c520e22b94b540873f72312614cc3fdca1 (diff) |
TIME LORD!
Bug: 14444180
Change-Id: I68bec3807c4d1c88d5af1aec2fe6907d60b5f2f3
-rw-r--r-- | core/java/android/view/Choreographer.java | 8 | ||||
-rw-r--r-- | core/java/android/view/ThreadedRenderer.java | 27 | ||||
-rw-r--r-- | core/jni/android_view_ThreadedRenderer.cpp | 13 | ||||
-rw-r--r-- | libs/hwui/Android.mk | 3 | ||||
-rw-r--r-- | libs/hwui/renderthread/CanvasContext.cpp | 5 | ||||
-rw-r--r-- | libs/hwui/renderthread/CanvasContext.h | 2 | ||||
-rw-r--r-- | libs/hwui/renderthread/DrawFrameTask.cpp | 22 | ||||
-rw-r--r-- | libs/hwui/renderthread/DrawFrameTask.h | 8 | ||||
-rw-r--r-- | libs/hwui/renderthread/RenderProxy.cpp | 20 | ||||
-rw-r--r-- | libs/hwui/renderthread/RenderProxy.h | 5 | ||||
-rw-r--r-- | libs/hwui/renderthread/RenderThread.cpp | 7 | ||||
-rw-r--r-- | libs/hwui/renderthread/RenderThread.h | 9 | ||||
-rw-r--r-- | libs/hwui/renderthread/TimeLord.cpp | 46 | ||||
-rw-r--r-- | libs/hwui/renderthread/TimeLord.h | 49 |
14 files changed, 181 insertions, 43 deletions
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java index f1523aefe04c..0a7607513378 100644 --- a/core/java/android/view/Choreographer.java +++ b/core/java/android/view/Choreographer.java @@ -259,6 +259,14 @@ public final class Choreographer { return delayMillis <= frameDelay ? 0 : delayMillis - frameDelay; } + /** + * @return The refresh rate as the nanoseconds between frames + * @hide + */ + long getFrameIntervalNanos() { + return mFrameIntervalNanos; + } + void dump(String prefix, PrintWriter writer) { String innerPrefix = prefix + " "; writer.print(prefix); writer.println("Choreographer:"); diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java index eaec8abe208b..89a2ea2cbda2 100644 --- a/core/java/android/view/ThreadedRenderer.java +++ b/core/java/android/view/ThreadedRenderer.java @@ -19,7 +19,6 @@ package android.view; import android.graphics.Bitmap; import android.graphics.Rect; import android.graphics.SurfaceTexture; -import android.os.SystemClock; import android.os.Trace; import android.view.Surface.OutOfResourcesException; import android.view.View.AttachInfo; @@ -52,16 +51,23 @@ public class ThreadedRenderer extends HardwareRenderer { private static final Rect NULL_RECT = new Rect(); + private static final long NANOS_PER_MS = 1000000; + private int mWidth, mHeight; private long mNativeProxy; private boolean mInitialized = false; private RenderNode mRootNode; + private Choreographer mChoreographer; ThreadedRenderer(boolean translucent) { long rootNodePtr = nCreateRootRenderNode(); mRootNode = RenderNode.adopt(rootNodePtr); mRootNode.setClipToBounds(false); mNativeProxy = nCreateProxy(translucent, rootNodePtr); + + // Setup timing + mChoreographer = Choreographer.getInstance(); + nSetFrameInterval(mNativeProxy, mChoreographer.getFrameIntervalNanos()); } @Override @@ -161,15 +167,6 @@ public class ThreadedRenderer extends HardwareRenderer { return false; } - /** - * TODO: Remove - * Temporary hack to allow RenderThreadTest prototype app to trigger - * replaying a DisplayList after modifying the displaylist properties - * - * @hide */ - public void repeatLastDraw() { - } - private void updateRootDisplayList(View view, HardwareDrawCallbacks callbacks) { view.mPrivateFlags |= View.PFLAG_DRAWN; @@ -194,7 +191,8 @@ public class ThreadedRenderer extends HardwareRenderer { @Override void draw(View view, AttachInfo attachInfo, HardwareDrawCallbacks callbacks, Rect dirty) { attachInfo.mIgnoreDirtyState = true; - attachInfo.mDrawingTime = SystemClock.uptimeMillis(); + long frameTimeNanos = mChoreographer.getFrameTimeNanos(); + attachInfo.mDrawingTime = frameTimeNanos / NANOS_PER_MS; updateRootDisplayList(view, callbacks); @@ -203,7 +201,8 @@ public class ThreadedRenderer extends HardwareRenderer { if (dirty == null) { dirty = NULL_RECT; } - nSyncAndDrawFrame(mNativeProxy, dirty.left, dirty.top, dirty.right, dirty.bottom); + nSyncAndDrawFrame(mNativeProxy, frameTimeNanos, + dirty.left, dirty.top, dirty.right, dirty.bottom); } @Override @@ -297,13 +296,15 @@ public class ThreadedRenderer extends HardwareRenderer { private static native long nCreateProxy(boolean translucent, long rootRenderNode); private static native void nDeleteProxy(long nativeProxy); + private static native void nSetFrameInterval(long nativeProxy, long frameIntervalNanos); + private static native boolean nInitialize(long nativeProxy, Surface window); private static native void nUpdateSurface(long nativeProxy, Surface window); private static native void nPauseSurface(long nativeProxy, Surface window); private static native void nSetup(long nativeProxy, int width, int height); private static native void nSetDisplayListData(long nativeProxy, long displayList, long newData); - private static native void nSyncAndDrawFrame(long nativeProxy, + private static native void nSyncAndDrawFrame(long nativeProxy, long frameTimeNanos, int dirtyLeft, int dirtyTop, int dirtyRight, int dirtyBottom); private static native void nRunWithGlContext(long nativeProxy, Runnable runnable); private static native void nDestroyCanvasAndSurface(long nativeProxy); diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp index 564c9a62ba99..6a0486725e84 100644 --- a/core/jni/android_view_ThreadedRenderer.cpp +++ b/core/jni/android_view_ThreadedRenderer.cpp @@ -152,6 +152,12 @@ static void android_view_ThreadedRenderer_deleteProxy(JNIEnv* env, jobject clazz delete proxy; } +static void android_view_ThreadedRenderer_setFrameInterval(JNIEnv* env, jobject clazz, + jlong proxyPtr, jlong frameIntervalNanos) { + RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr); + proxy->setFrameInterval(frameIntervalNanos); +} + static jboolean android_view_ThreadedRenderer_initialize(JNIEnv* env, jobject clazz, jlong proxyPtr, jobject jsurface) { RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr); @@ -186,10 +192,10 @@ static void android_view_ThreadedRenderer_setup(JNIEnv* env, jobject clazz, } static void android_view_ThreadedRenderer_syncAndDrawFrame(JNIEnv* env, jobject clazz, - jlong proxyPtr, jint dirtyLeft, jint dirtyTop, + jlong proxyPtr, jlong frameTimeNanos, jint dirtyLeft, jint dirtyTop, jint dirtyRight, jint dirtyBottom) { RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr); - proxy->syncAndDrawFrame(dirtyLeft, dirtyTop, dirtyRight, dirtyBottom); + proxy->syncAndDrawFrame(frameTimeNanos, dirtyLeft, dirtyTop, dirtyRight, dirtyBottom); } static void android_view_ThreadedRenderer_destroyCanvasAndSurface(JNIEnv* env, jobject clazz, @@ -261,11 +267,12 @@ static JNINativeMethod gMethods[] = { { "nCreateRootRenderNode", "()J", (void*) android_view_ThreadedRenderer_createRootRenderNode }, { "nCreateProxy", "(ZJ)J", (void*) android_view_ThreadedRenderer_createProxy }, { "nDeleteProxy", "(J)V", (void*) android_view_ThreadedRenderer_deleteProxy }, + { "nSetFrameInterval", "(JJ)V", (void*) android_view_ThreadedRenderer_setFrameInterval }, { "nInitialize", "(JLandroid/view/Surface;)Z", (void*) android_view_ThreadedRenderer_initialize }, { "nUpdateSurface", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_updateSurface }, { "nPauseSurface", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_pauseSurface }, { "nSetup", "(JII)V", (void*) android_view_ThreadedRenderer_setup }, - { "nSyncAndDrawFrame", "(JIIII)V", (void*) android_view_ThreadedRenderer_syncAndDrawFrame }, + { "nSyncAndDrawFrame", "(JJIIII)V", (void*) android_view_ThreadedRenderer_syncAndDrawFrame }, { "nDestroyCanvasAndSurface", "(J)V", (void*) android_view_ThreadedRenderer_destroyCanvasAndSurface }, { "nInvokeFunctor", "(JJZ)V", (void*) android_view_ThreadedRenderer_invokeFunctor }, { "nRunWithGlContext", "(JLjava/lang/Runnable;)V", (void*) android_view_ThreadedRenderer_runWithGlContext }, diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk index d324439dbc56..eb0cac8944df 100644 --- a/libs/hwui/Android.mk +++ b/libs/hwui/Android.mk @@ -59,7 +59,8 @@ ifeq ($(USE_OPENGL_RENDERER),true) renderthread/DrawFrameTask.cpp \ renderthread/RenderProxy.cpp \ renderthread/RenderTask.cpp \ - renderthread/RenderThread.cpp + renderthread/RenderThread.cpp \ + renderthread/TimeLord.cpp intermediates := $(call intermediates-dir-for,STATIC_LIBRARIES,libRS,TARGET,) diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index 63f4b9538741..f199236b21be 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -406,6 +406,8 @@ void CanvasContext::processLayerUpdates(const Vector<DeferredLayerUpdater*>* lay } void CanvasContext::prepareTree(TreeInfo& info) { + info.frameTimeMs = mRenderThread.timeLord().frameTimeMs(); + mRootRenderNode->prepareTree(info); if (info.hasAnimations && !info.hasFunctors) { @@ -449,12 +451,11 @@ void CanvasContext::draw(Rect* dirty) { } // Called by choreographer to do an RT-driven animation -void CanvasContext::doFrame(nsecs_t frameTimeNanos) { +void CanvasContext::doFrame() { ATRACE_CALL(); TreeInfo info; info.evaluateAnimations = true; - info.frameTimeMs = nanoseconds_to_milliseconds(frameTimeNanos); info.performStagingPush = false; info.prepareTextures = false; diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h index 0873ad4f9017..8022c9e94958 100644 --- a/libs/hwui/renderthread/CanvasContext.h +++ b/libs/hwui/renderthread/CanvasContext.h @@ -59,7 +59,7 @@ public: void destroyCanvasAndSurface(); // IFrameCallback, Chroreographer-driven frame callback entry point - virtual void doFrame(nsecs_t frameTimeNanos); + virtual void doFrame(); bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap); diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp index 45f5cb057ee4..a7b781a21514 100644 --- a/libs/hwui/renderthread/DrawFrameTask.cpp +++ b/libs/hwui/renderthread/DrawFrameTask.cpp @@ -30,13 +30,17 @@ namespace android { namespace uirenderer { namespace renderthread { -DrawFrameTask::DrawFrameTask() : mContext(0) { +DrawFrameTask::DrawFrameTask() + : mRenderThread(NULL) + , mContext(NULL) + , mFrameTimeNanos(NULL) { } DrawFrameTask::~DrawFrameTask() { } -void DrawFrameTask::setContext(CanvasContext* context) { +void DrawFrameTask::setContext(RenderThread* thread, CanvasContext* context) { + mRenderThread = thread; mContext = context; } @@ -59,18 +63,20 @@ void DrawFrameTask::setDirty(int left, int top, int right, int bottom) { mDirty.set(left, top, right, bottom); } -void DrawFrameTask::drawFrame(RenderThread* renderThread) { +void DrawFrameTask::drawFrame(nsecs_t frameTimeNanos) { LOG_ALWAYS_FATAL_IF(!mContext, "Cannot drawFrame with no CanvasContext!"); - postAndWait(renderThread); + mFrameTimeNanos = frameTimeNanos; + postAndWait(); // Reset the single-frame data + mFrameTimeNanos = 0; mDirty.setEmpty(); } -void DrawFrameTask::postAndWait(RenderThread* renderThread) { +void DrawFrameTask::postAndWait() { AutoMutex _lock(mLock); - renderThread->queue(this); + mRenderThread->queue(this); mSignal.wait(mLock); } @@ -99,13 +105,11 @@ static void initTreeInfo(TreeInfo& info) { info.prepareTextures = true; info.performStagingPush = true; info.evaluateAnimations = true; - // TODO: Get this from Choreographer - nsecs_t frameTimeNs = systemTime(CLOCK_MONOTONIC); - info.frameTimeMs = nanoseconds_to_milliseconds(frameTimeNs); } bool DrawFrameTask::syncFrameState() { ATRACE_CALL(); + mRenderThread->timeLord().vsyncReceived(mFrameTimeNanos); mContext->makeCurrent(); Caches::getInstance().textureCache.resetMarkInUse(); TreeInfo info; diff --git a/libs/hwui/renderthread/DrawFrameTask.h b/libs/hwui/renderthread/DrawFrameTask.h index c2808686f369..ea009004a797 100644 --- a/libs/hwui/renderthread/DrawFrameTask.h +++ b/libs/hwui/renderthread/DrawFrameTask.h @@ -48,30 +48,32 @@ public: DrawFrameTask(); virtual ~DrawFrameTask(); - void setContext(CanvasContext* context); + void setContext(RenderThread* thread, CanvasContext* context); void addLayer(DeferredLayerUpdater* layer); void removeLayer(DeferredLayerUpdater* layer); void setDirty(int left, int top, int right, int bottom); - void drawFrame(RenderThread* renderThread); + void drawFrame(nsecs_t frameTimeNanos); virtual void run(); private: - void postAndWait(RenderThread* renderThread); + void postAndWait(); bool syncFrameState(); void unblockUiThread(); Mutex mLock; Condition mSignal; + RenderThread* mRenderThread; CanvasContext* mContext; /********************************************* * Single frame data *********************************************/ Rect mDirty; + nsecs_t mFrameTimeNanos; /********************************************* * Multi frame data diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp index 87886e6dc697..7b7c019d0623 100644 --- a/libs/hwui/renderthread/RenderProxy.cpp +++ b/libs/hwui/renderthread/RenderProxy.cpp @@ -62,7 +62,7 @@ RenderProxy::RenderProxy(bool translucent, RenderNode* rootRenderNode) args->translucent = translucent; args->rootRenderNode = rootRenderNode; mContext = (CanvasContext*) postAndWait(task); - mDrawFrameTask.setContext(mContext); + mDrawFrameTask.setContext(&mRenderThread, mContext); } RenderProxy::~RenderProxy() { @@ -79,13 +79,25 @@ void RenderProxy::destroyContext() { SETUP_TASK(destroyContext); args->context = mContext; mContext = 0; - mDrawFrameTask.setContext(0); + mDrawFrameTask.setContext(NULL, NULL); // This is also a fence as we need to be certain that there are no // outstanding mDrawFrame tasks posted before it is destroyed postAndWait(task); } } +CREATE_BRIDGE2(setFrameInterval, RenderThread* thread, nsecs_t frameIntervalNanos) { + args->thread->timeLord().setFrameInterval(args->frameIntervalNanos); + return NULL; +} + +void RenderProxy::setFrameInterval(nsecs_t frameIntervalNanos) { + SETUP_TASK(setFrameInterval); + args->thread = &mRenderThread; + args->frameIntervalNanos = frameIntervalNanos; + post(task); +} + CREATE_BRIDGE2(initialize, CanvasContext* context, EGLNativeWindowType window) { return (void*) args->context->initialize(args->window); } @@ -134,10 +146,10 @@ void RenderProxy::setup(int width, int height) { post(task); } -void RenderProxy::syncAndDrawFrame( +void RenderProxy::syncAndDrawFrame(nsecs_t frameTimeNanos, int dirtyLeft, int dirtyTop, int dirtyRight, int dirtyBottom) { mDrawFrameTask.setDirty(dirtyLeft, dirtyTop, dirtyRight, dirtyBottom); - mDrawFrameTask.drawFrame(&mRenderThread); + mDrawFrameTask.drawFrame(frameTimeNanos); } CREATE_BRIDGE1(destroyCanvasAndSurface, CanvasContext* context) { diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h index eab139528eab..bfa2b8db72b8 100644 --- a/libs/hwui/renderthread/RenderProxy.h +++ b/libs/hwui/renderthread/RenderProxy.h @@ -25,6 +25,7 @@ #include <utils/Condition.h> #include <utils/Functor.h> #include <utils/Mutex.h> +#include <utils/Timers.h> #include <utils/StrongPointer.h> #include <utils/Vector.h> @@ -59,11 +60,13 @@ public: ANDROID_API RenderProxy(bool translucent, RenderNode* rootNode); ANDROID_API virtual ~RenderProxy(); + ANDROID_API void setFrameInterval(nsecs_t frameIntervalNanos); + ANDROID_API bool initialize(const sp<ANativeWindow>& window); ANDROID_API void updateSurface(const sp<ANativeWindow>& window); ANDROID_API void pauseSurface(const sp<ANativeWindow>& window); ANDROID_API void setup(int width, int height); - ANDROID_API void syncAndDrawFrame( + ANDROID_API void syncAndDrawFrame(nsecs_t frameTimeNanos, int dirtyLeft, int dirtyTop, int dirtyRight, int dirtyBottom); ANDROID_API void destroyCanvasAndSurface(); diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp index e95707a396f2..35a3eabce925 100644 --- a/libs/hwui/renderthread/RenderThread.cpp +++ b/libs/hwui/renderthread/RenderThread.cpp @@ -129,8 +129,7 @@ RenderThread::RenderThread() : Thread(true), Singleton<RenderThread>() , mDisplayEventReceiver(0) , mVsyncRequested(false) , mFrameCallbackTaskPending(false) - , mFrameCallbackTask(0) - , mFrameTime(0) { + , mFrameCallbackTask(0) { mFrameCallbackTask = new DispatchFrameCallbacks(this); mLooper = new Looper(false); run("RenderThread"); @@ -193,7 +192,7 @@ void RenderThread::drainDisplayEventQueue() { nsecs_t vsyncEvent = latestVsyncEvent(mDisplayEventReceiver); if (vsyncEvent > 0) { mVsyncRequested = false; - mFrameTime = vsyncEvent; + mTimeLord.vsyncReceived(vsyncEvent); if (!mFrameCallbackTaskPending) { mFrameCallbackTaskPending = true; //queueDelayed(mFrameCallbackTask, DISPATCH_FRAME_CALLBACKS_DELAY); @@ -209,7 +208,7 @@ void RenderThread::dispatchFrameCallbacks() { mFrameCallbacks.swap(callbacks); for (std::set<IFrameCallback*>::iterator it = callbacks.begin(); it != callbacks.end(); it++) { - (*it)->doFrame(mFrameTime); + (*it)->doFrame(); } } diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h index b93dfd65fb34..215d29413f68 100644 --- a/libs/hwui/renderthread/RenderThread.h +++ b/libs/hwui/renderthread/RenderThread.h @@ -28,6 +28,8 @@ #include <utils/Singleton.h> #include <utils/Thread.h> +#include "TimeLord.h" + namespace android { class DisplayEventReceiver; @@ -53,7 +55,7 @@ private: // Mimics android.view.Choreographer.FrameCallback class IFrameCallback { public: - virtual void doFrame(nsecs_t frameTimeNanos) = 0; + virtual void doFrame() = 0; protected: ~IFrameCallback() {} @@ -71,6 +73,8 @@ public: void postFrameCallback(IFrameCallback* callback); void removeFrameCallback(IFrameCallback* callback); + TimeLord& timeLord() { return mTimeLord; } + protected: virtual bool threadLoop(); @@ -102,7 +106,8 @@ private: std::set<IFrameCallback*> mFrameCallbacks; bool mFrameCallbackTaskPending; DispatchFrameCallbacks* mFrameCallbackTask; - nsecs_t mFrameTime; + + TimeLord mTimeLord; }; } /* namespace renderthread */ diff --git a/libs/hwui/renderthread/TimeLord.cpp b/libs/hwui/renderthread/TimeLord.cpp new file mode 100644 index 000000000000..758d96e96043 --- /dev/null +++ b/libs/hwui/renderthread/TimeLord.cpp @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2014 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. + */ +#include "TimeLord.h" + +namespace android { +namespace uirenderer { +namespace renderthread { + +TimeLord::TimeLord() + : mFrameIntervalNanos(0) + , mFrameTimeNanos(0) { +} + +void TimeLord::vsyncReceived(nsecs_t vsync) { + if (vsync > mFrameTimeNanos) { + mFrameTimeNanos = vsync; + } +} + +nsecs_t TimeLord::frameTimeMs() { + // Logic copied from Choreographer.java + nsecs_t now = systemTime(CLOCK_MONOTONIC); + nsecs_t jitterNanos = now - mFrameTimeNanos; + if (jitterNanos >= mFrameIntervalNanos) { + nsecs_t lastFrameOffset = jitterNanos % mFrameIntervalNanos; + mFrameTimeNanos = now - lastFrameOffset; + } + return nanoseconds_to_milliseconds(mFrameTimeNanos); +} + +} /* namespace renderthread */ +} /* namespace uirenderer */ +} /* namespace android */ diff --git a/libs/hwui/renderthread/TimeLord.h b/libs/hwui/renderthread/TimeLord.h new file mode 100644 index 000000000000..52c6d9ef7448 --- /dev/null +++ b/libs/hwui/renderthread/TimeLord.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2014 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. + */ +#ifndef TIMELORD_H +#define TIMELORD_H + +#include <utils/Timers.h> + +namespace android { +namespace uirenderer { +namespace renderthread { + +class RenderThread; + +// This class serves as a helper to filter & manage frame times from multiple sources +// ensuring that time flows linearly and smoothly +class TimeLord { +public: + void setFrameInterval(nsecs_t intervalNanos) { mFrameIntervalNanos = intervalNanos; } + void vsyncReceived(nsecs_t vsync); + nsecs_t frameTimeMs(); + +private: + friend class RenderThread; + + TimeLord(); + ~TimeLord() {} + + nsecs_t mFrameIntervalNanos; + nsecs_t mFrameTimeNanos; +}; + +} /* namespace renderthread */ +} /* namespace uirenderer */ +} /* namespace android */ + +#endif /* TIMELORD_H */ |