TIME LORD!
Bug: 14444180 Change-Id: I68bec3807c4d1c88d5af1aec2fe6907d60b5f2f3
This commit is contained in:
@@ -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:");
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 },
|
||||
|
||||
@@ -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,)
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
46
libs/hwui/renderthread/TimeLord.cpp
Normal file
46
libs/hwui/renderthread/TimeLord.cpp
Normal file
@@ -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 */
|
||||
49
libs/hwui/renderthread/TimeLord.h
Normal file
49
libs/hwui/renderthread/TimeLord.h
Normal file
@@ -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 */
|
||||
Reference in New Issue
Block a user