1d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi/* 2d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi * Copyright (C) 2017 The Android Open Source Project 3d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi * 4d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi * Licensed under the Apache License, Version 2.0 (the "License"); 5d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi * you may not use this file except in compliance with the License. 6d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi * You may obtain a copy of the License at 7d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi * 8d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi * http://www.apache.org/licenses/LICENSE-2.0 9d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi * 10d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi * Unless required by applicable law or agreed to in writing, software 11d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi * distributed under the License is distributed on an "AS IS" BASIS, 12d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi * See the License for the specific language governing permissions and 14d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi * limitations under the License 15d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi */ 16d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi 17d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggipackage com.android.internal.view; 18d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi 19d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggiimport android.os.Handler; 20d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggiimport android.os.Message; 21d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggiimport android.view.Choreographer; 22d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggiimport android.view.Display; 23d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi 24d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi/** 25d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi * Utility class to schedule things at vsync-sf instead of vsync-app 26d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi * @hide 27d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi */ 28d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggipublic class SurfaceFlingerVsyncChoreographer { 29d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi 30d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi private static final long ONE_MS_IN_NS = 1000000; 31d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi private static final long ONE_S_IN_NS = ONE_MS_IN_NS * 1000; 32d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi 33d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi private final Handler mHandler; 34ed7993b5d147a6741d26fe0b16cc9fa5e34ceaeeJorim Jaggi private final Choreographer mChoreographer; 35d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi 36d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi /** 37d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi * The offset between vsync-app and vsync-surfaceflinger. See 38d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi * {@link #calculateAppSurfaceFlingerVsyncOffsetMs} why this is necessary. 39d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi */ 40d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi private long mSurfaceFlingerOffsetMs; 41d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi 42ed7993b5d147a6741d26fe0b16cc9fa5e34ceaeeJorim Jaggi public SurfaceFlingerVsyncChoreographer(Handler handler, Display display, 43ed7993b5d147a6741d26fe0b16cc9fa5e34ceaeeJorim Jaggi Choreographer choreographer) { 44d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi mHandler = handler; 45ed7993b5d147a6741d26fe0b16cc9fa5e34ceaeeJorim Jaggi mChoreographer = choreographer; 46d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi mSurfaceFlingerOffsetMs = calculateAppSurfaceFlingerVsyncOffsetMs(display); 47d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi } 48d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi 49d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi public long getSurfaceFlingerOffsetMs() { 50d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi return mSurfaceFlingerOffsetMs; 51d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi } 52d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi 53d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi /** 54d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi * This method calculates the offset between vsync-surfaceflinger and vsync-app. If vsync-app 55d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi * is a couple of milliseconds before vsync-sf, a touch or animation event that causes a surface 56d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi * flinger transaction are sometimes processed before the vsync-sf tick, and sometimes after, 57d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi * which leads to jank. Figure out this difference here and then post all the touch/animation 58d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi * events to start being processed at vsync-sf. 59d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi * 60d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi * @return The offset between vsync-app and vsync-sf, or 0 if vsync app happens after vsync-sf. 61d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi */ 62d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi private long calculateAppSurfaceFlingerVsyncOffsetMs(Display display) { 63d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi 64d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi // Calculate vsync offset from SurfaceFlinger. 65d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi // See frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp:getDisplayConfigs 66d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi long vsyncPeriod = (long) (ONE_S_IN_NS / display.getRefreshRate()); 67d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi long sfVsyncOffset = vsyncPeriod - (display.getPresentationDeadlineNanos() - ONE_MS_IN_NS); 68d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi return Math.max(0, (sfVsyncOffset - display.getAppVsyncOffsetNanos()) / ONE_MS_IN_NS); 69d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi } 70d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi 71d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi public void scheduleAtSfVsync(Runnable r) { 72d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi final long delay = calculateDelay(); 73d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi if (delay <= 0) { 74d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi r.run(); 75d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi } else { 76d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi mHandler.postDelayed(r, delay); 77d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi } 78d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi } 79d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi 80d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi public void scheduleAtSfVsync(Handler h, Message m) { 81d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi final long delay = calculateDelay(); 82d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi if (delay <= 0) { 83d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi h.handleMessage(m); 84d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi } else { 85d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi m.setAsynchronous(true); 86d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi h.sendMessageDelayed(m, delay); 87d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi } 88d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi } 89d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi 90d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi private long calculateDelay() { 91d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi final long sinceFrameStart = System.nanoTime() - mChoreographer.getLastFrameTimeNanos(); 92d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi return mSurfaceFlingerOffsetMs - sinceFrameStart / 1000000; 93d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi } 94d6d6de6da4c7c32babd65c23804d9fdc6eeed740Jorim Jaggi} 95