PageRenderTime 87ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/tests/SurfaceComposition/src/android/surfacecomposition/CustomSurfaceView.java

https://gitlab.com/amardeep434/nitro_base
Java | 243 lines | 175 code | 21 blank | 47 comment | 27 complexity | a377d876fef15b83c7260536e4ba0345 MD5 | raw file
  1. /*
  2. * Copyright (C) 2015 The Android Open Source Project
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package android.surfacecomposition;
  17. import java.util.Random;
  18. import android.content.Context;
  19. import android.graphics.Canvas;
  20. import android.graphics.Paint;
  21. import android.view.Surface;
  22. import android.view.SurfaceHolder;
  23. import android.view.SurfaceView;
  24. /**
  25. * This provides functionality to measure Surface update frame rate. The idea is to
  26. * constantly invalidates Surface in a separate thread. Lowest possible way is to
  27. * use SurfaceView which works with Surface. This gives a very small overhead
  28. * and very close to Android internals. Note, that lockCanvas is blocking
  29. * methods and it returns once SurfaceFlinger consumes previous buffer. This
  30. * gives the change to measure real performance of Surface compositor.
  31. */
  32. public class CustomSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
  33. private final static long DURATION_TO_WARMUP_MS = 50;
  34. private final static long DURATION_TO_MEASURE_ROUGH_MS = 500;
  35. private final static long DURATION_TO_MEASURE_PRECISE_MS = 3000;
  36. private final static Random mRandom = new Random();
  37. private final Object mSurfaceLock = new Object();
  38. private Surface mSurface;
  39. private boolean mDrawNameOnReady = true;
  40. private boolean mSurfaceWasChanged = false;
  41. private String mName;
  42. private Canvas mCanvas;
  43. class ValidateThread extends Thread {
  44. private double mFPS = 0.0f;
  45. // Used to support early exit and prevent long computation.
  46. private double mBadFPS;
  47. private double mPerfectFPS;
  48. ValidateThread(double badFPS, double perfectFPS) {
  49. mBadFPS = badFPS;
  50. mPerfectFPS = perfectFPS;
  51. }
  52. public void run() {
  53. long startTime = System.currentTimeMillis();
  54. while (System.currentTimeMillis() - startTime < DURATION_TO_WARMUP_MS) {
  55. invalidateSurface(false);
  56. }
  57. startTime = System.currentTimeMillis();
  58. long endTime;
  59. int frameCnt = 0;
  60. while (true) {
  61. invalidateSurface(false);
  62. endTime = System.currentTimeMillis();
  63. ++frameCnt;
  64. mFPS = (double)frameCnt * 1000.0 / (endTime - startTime);
  65. if ((endTime - startTime) >= DURATION_TO_MEASURE_ROUGH_MS) {
  66. // Test if result looks too bad or perfect and stop early.
  67. if (mFPS <= mBadFPS || mFPS >= mPerfectFPS) {
  68. break;
  69. }
  70. }
  71. if ((endTime - startTime) >= DURATION_TO_MEASURE_PRECISE_MS) {
  72. break;
  73. }
  74. }
  75. }
  76. public double getFPS() {
  77. return mFPS;
  78. }
  79. }
  80. public CustomSurfaceView(Context context, String name) {
  81. super(context);
  82. mName = name;
  83. getHolder().addCallback(this);
  84. }
  85. public void setMode(int pixelFormat, boolean drawNameOnReady) {
  86. mDrawNameOnReady = drawNameOnReady;
  87. getHolder().setFormat(pixelFormat);
  88. }
  89. public void acquireCanvas() {
  90. synchronized (mSurfaceLock) {
  91. if (mCanvas != null) {
  92. throw new RuntimeException("Surface canvas was already acquired.");
  93. }
  94. if (mSurface != null) {
  95. mCanvas = mSurface.lockCanvas(null);
  96. }
  97. }
  98. }
  99. public void releaseCanvas() {
  100. synchronized (mSurfaceLock) {
  101. if (mCanvas != null) {
  102. if (mSurface == null) {
  103. throw new RuntimeException(
  104. "Surface was destroyed but canvas was not released.");
  105. }
  106. mSurface.unlockCanvasAndPost(mCanvas);
  107. mCanvas = null;
  108. }
  109. }
  110. }
  111. /**
  112. * Invalidate surface.
  113. */
  114. private void invalidateSurface(boolean drawSurfaceId) {
  115. synchronized (mSurfaceLock) {
  116. if (mSurface != null) {
  117. Canvas canvas = mSurface.lockCanvas(null);
  118. // Draw surface name for debug purpose only. This does not affect the test
  119. // because it is drawn only during allocation.
  120. if (drawSurfaceId) {
  121. int textSize = canvas.getHeight() / 24;
  122. Paint paint = new Paint();
  123. paint.setTextSize(textSize);
  124. int textWidth = (int)(paint.measureText(mName) + 0.5f);
  125. int x = mRandom.nextInt(canvas.getWidth() - textWidth);
  126. int y = textSize + mRandom.nextInt(canvas.getHeight() - textSize);
  127. // Create effect of fog to visually control correctness of composition.
  128. paint.setColor(0xFFFF8040);
  129. canvas.drawARGB(32, 255, 255, 255);
  130. canvas.drawText(mName, x, y, paint);
  131. }
  132. mSurface.unlockCanvasAndPost(canvas);
  133. }
  134. }
  135. }
  136. /**
  137. * Wait until surface is created and ready to use or return immediately if surface
  138. * already exists.
  139. */
  140. public void waitForSurfaceReady() {
  141. synchronized (mSurfaceLock) {
  142. if (mSurface == null) {
  143. try {
  144. mSurfaceLock.wait(5000);
  145. } catch(InterruptedException e) {
  146. e.printStackTrace();
  147. }
  148. }
  149. if (mSurface == null)
  150. throw new RuntimeException("Surface is not ready.");
  151. mSurfaceWasChanged = false;
  152. }
  153. }
  154. /**
  155. * Wait until surface is destroyed or return immediately if surface does not exist.
  156. */
  157. public void waitForSurfaceDestroyed() {
  158. synchronized (mSurfaceLock) {
  159. if (mSurface != null) {
  160. try {
  161. mSurfaceLock.wait(5000);
  162. } catch(InterruptedException e) {
  163. e.printStackTrace();
  164. }
  165. }
  166. if (mSurface != null)
  167. throw new RuntimeException("Surface still exists.");
  168. mSurfaceWasChanged = false;
  169. }
  170. }
  171. /**
  172. * Validate that surface has not been changed since waitForSurfaceReady or
  173. * waitForSurfaceDestroyed.
  174. */
  175. public void validateSurfaceNotChanged() {
  176. synchronized (mSurfaceLock) {
  177. if (mSurfaceWasChanged) {
  178. throw new RuntimeException("Surface was changed during the test execution.");
  179. }
  180. }
  181. }
  182. public double measureFPS(double badFPS, double perfectFPS) {
  183. try {
  184. ValidateThread validateThread = new ValidateThread(badFPS, perfectFPS);
  185. validateThread.start();
  186. validateThread.join();
  187. return validateThread.getFPS();
  188. } catch (InterruptedException e) {
  189. throw new RuntimeException(e);
  190. }
  191. }
  192. @Override
  193. public void surfaceCreated(SurfaceHolder holder) {
  194. synchronized (mSurfaceLock) {
  195. mSurfaceWasChanged = true;
  196. }
  197. }
  198. @Override
  199. public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
  200. // This method is always called at least once, after surfaceCreated.
  201. synchronized (mSurfaceLock) {
  202. mSurface = holder.getSurface();
  203. // We only need to invalidate the surface for the compositor performance test so that
  204. // it gets included in the composition process. For allocation performance we
  205. // don't need to invalidate surface and this allows us to remove non-necessary
  206. // surface invalidation from the test.
  207. if (mDrawNameOnReady) {
  208. invalidateSurface(true);
  209. }
  210. mSurfaceWasChanged = true;
  211. mSurfaceLock.notify();
  212. }
  213. }
  214. @Override
  215. public void surfaceDestroyed(SurfaceHolder holder) {
  216. synchronized (mSurfaceLock) {
  217. mSurface = null;
  218. mSurfaceWasChanged = true;
  219. mSurfaceLock.notify();
  220. }
  221. }
  222. }