19dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel/* 29dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel * Copyright (C) 2015 The Android Open Source Project 39dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel * 49dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel * Licensed under the Apache License, Version 2.0 (the "License"); 59dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel * you may not use this file except in compliance with the License. 69dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel * You may obtain a copy of the License at 79dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel * 89dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel * http://www.apache.org/licenses/LICENSE-2.0 99dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel * 109dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel * Unless required by applicable law or agreed to in writing, software 119dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel * distributed under the License is distributed on an "AS IS" BASIS, 129dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel * See the License for the specific language governing permissions and 149dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel * limitations under the License. 159dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel */ 169dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmelpackage android.surfacecomposition; 179dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel 189dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmelimport java.text.DecimalFormat; 199dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmelimport java.util.ArrayList; 209dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmelimport java.util.List; 219dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel 229dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmelimport android.app.ActionBar; 239dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmelimport android.app.Activity; 249dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmelimport android.app.ActivityManager; 259dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmelimport android.app.ActivityManager.MemoryInfo; 269dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmelimport android.content.Context; 277578d10f6cb2203ba3575b82b4b67e3a5d448bd7Yury Khmelimport android.content.pm.PackageManager; 289dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmelimport android.graphics.Color; 299dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmelimport android.graphics.PixelFormat; 309dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmelimport android.graphics.Rect; 319dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmelimport android.graphics.drawable.ColorDrawable; 329dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmelimport android.os.Bundle; 339dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmelimport android.view.Display; 349dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmelimport android.view.View; 359dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmelimport android.view.View.OnClickListener; 369dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmelimport android.view.ViewGroup; 379dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmelimport android.view.Window; 389dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmelimport android.view.WindowManager; 399dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmelimport android.widget.ArrayAdapter; 409dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmelimport android.widget.Button; 419dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmelimport android.widget.LinearLayout; 429dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmelimport android.widget.RelativeLayout; 439dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmelimport android.widget.Spinner; 449dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmelimport android.widget.TextView; 459dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel 469dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel/** 479dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel * This activity is designed to measure peformance scores of Android surfaces. 489dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel * It can work in two modes. In first mode functionality of this activity is 499dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel * invoked from Cts test (SurfaceCompositionTest). This activity can also be 509dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel * used in manual mode as a normal app. Different pixel formats are supported. 519dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel * 529dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel * measureCompositionScore(pixelFormat) 539dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel * This test measures surface compositor performance which shows how many 549dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel * surfaces of specific format surface compositor can combine without dropping 559dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel * frames. We allow one dropped frame per half second. 569dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel * 579dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel * measureAllocationScore(pixelFormat) 589dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel * This test measures surface allocation/deallocation performance. It shows 599dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel * how many surface lifecycles (creation, destruction) can be done per second. 609dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel * 619dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel * In manual mode, which activated by pressing button 'Compositor speed' or 629dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel * 'Allocator speed', all possible pixel format are tested and combined result 639dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel * is displayed in text view. Additional system information such as memory 649dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel * status, display size and surface format is also displayed and regulary 659dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel * updated. 669dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel */ 679dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmelpublic class SurfaceCompositionMeasuringActivity extends Activity implements OnClickListener { 689dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel private final static int MIN_NUMBER_OF_SURFACES = 15; 699dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel private final static int MAX_NUMBER_OF_SURFACES = 40; 709dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel private final static int WARM_UP_ALLOCATION_CYCLES = 2; 719dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel private final static int MEASURE_ALLOCATION_CYCLES = 5; 729dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel private final static int TEST_COMPOSITOR = 1; 739dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel private final static int TEST_ALLOCATION = 2; 749dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel private final static float MIN_REFRESH_RATE_SUPPORTED = 50.0f; 759dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel 769dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel private final static DecimalFormat DOUBLE_FORMAT = new DecimalFormat("#.00"); 779dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel // Possible selection in pixel format selector. 789dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel private final static int[] PIXEL_FORMATS = new int[] { 799dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel PixelFormat.TRANSLUCENT, 809dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel PixelFormat.TRANSPARENT, 819dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel PixelFormat.OPAQUE, 829dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel PixelFormat.RGBA_8888, 839dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel PixelFormat.RGBX_8888, 849dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel PixelFormat.RGB_888, 859dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel PixelFormat.RGB_565, 869dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel }; 879dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel 889dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel 899dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel private List<CustomSurfaceView> mViews = new ArrayList<CustomSurfaceView>(); 909dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel private Button mMeasureCompositionButton; 919dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel private Button mMeasureAllocationButton; 929dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel private Spinner mPixelFormatSelector; 939dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel private TextView mResultView; 949dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel private TextView mSystemInfoView; 959dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel private final Object mLockResumed = new Object(); 969dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel private boolean mResumed; 979dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel 989dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel // Drop one frame per half second. 999dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel private double mRefreshRate; 1009dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel private double mTargetFPS; 1017578d10f6cb2203ba3575b82b4b67e3a5d448bd7Yury Khmel private boolean mAndromeda; 1029dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel 1039dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel private int mWidth; 1049dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel private int mHeight; 1059dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel 1069dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel class CompositorScore { 1079dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel double mSurfaces; 1089e433bba26f3520baeb9a341069a4ff34e460410Yury Khmel double mBandwidth; 1099dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel 1109dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel @Override 1119dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel public String toString() { 1129dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel return DOUBLE_FORMAT.format(mSurfaces) + " surfaces. " + 1139e433bba26f3520baeb9a341069a4ff34e460410Yury Khmel "Bandwidth: " + getReadableMemory((long)mBandwidth) + "/s"; 1149dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 1159dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 1169dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel 1179dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel /** 1189dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel * Measure performance score. 1199dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel * 1209dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel * @return biggest possible number of visible surfaces which surface 1219dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel * compositor can handle. 1229dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel */ 1239dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel public CompositorScore measureCompositionScore(int pixelFormat) { 1249dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel waitForActivityResumed(); 1259dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel //MemoryAccessTask memAccessTask = new MemoryAccessTask(); 1269dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel //memAccessTask.start(); 1279dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel // Destroy any active surface. 1289dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel configureSurfacesAndWait(0, pixelFormat, false); 1299dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel CompositorScore score = new CompositorScore(); 1309dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel score.mSurfaces = measureCompositionScore(new Measurement(0, 60.0), 1319dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel new Measurement(mViews.size() + 1, 0.0f), pixelFormat); 1329dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel // Assume 32 bits per pixel. 1339e433bba26f3520baeb9a341069a4ff34e460410Yury Khmel score.mBandwidth = score.mSurfaces * mTargetFPS * mWidth * mHeight * 4.0; 1349dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel //memAccessTask.stop(); 1359dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel return score; 1369dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 1379dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel 1389dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel static class AllocationScore { 1399dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel double mMedian; 1409dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel double mMin; 1419dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel double mMax; 1429dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel 1439dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel @Override 1449dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel public String toString() { 1459dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel return DOUBLE_FORMAT.format(mMedian) + " (min:" + DOUBLE_FORMAT.format(mMin) + 1469dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel ", max:" + DOUBLE_FORMAT.format(mMax) + ") surface allocations per second"; 1479dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 1489dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 1499dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel 1509dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel public AllocationScore measureAllocationScore(int pixelFormat) { 1519dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel waitForActivityResumed(); 1529dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel AllocationScore score = new AllocationScore(); 1539dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel for (int i = 0; i < MEASURE_ALLOCATION_CYCLES + WARM_UP_ALLOCATION_CYCLES; ++i) { 1549dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel long time1 = System.currentTimeMillis(); 1559dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel configureSurfacesAndWait(MIN_NUMBER_OF_SURFACES, pixelFormat, false); 1569dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel acquireSurfacesCanvas(); 1579dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel long time2 = System.currentTimeMillis(); 1589dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel releaseSurfacesCanvas(); 1599dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel configureSurfacesAndWait(0, pixelFormat, false); 1609dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel // Give SurfaceFlinger some time to rebuild the layer stack and release the buffers. 1619dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel try { 1629dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel Thread.sleep(500); 1639dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } catch(InterruptedException e) { 1649dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel e.printStackTrace(); 1659dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 1669dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel if (i < WARM_UP_ALLOCATION_CYCLES) { 1679dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel // This is warm-up cycles, ignore result so far. 1689dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel continue; 1699dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 1709dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel double speed = MIN_NUMBER_OF_SURFACES * 1000.0 / (time2 - time1); 1719dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel score.mMedian += speed / MEASURE_ALLOCATION_CYCLES; 1729dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel if (i == WARM_UP_ALLOCATION_CYCLES) { 1739dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel score.mMin = speed; 1749dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel score.mMax = speed; 1759dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } else { 1769dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel score.mMin = Math.min(score.mMin, speed); 1779dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel score.mMax = Math.max(score.mMax, speed); 1789dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 1799dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 1809dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel 1819dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel return score; 1829dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 1839dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel 1847578d10f6cb2203ba3575b82b4b67e3a5d448bd7Yury Khmel public boolean isAndromeda() { 1857578d10f6cb2203ba3575b82b4b67e3a5d448bd7Yury Khmel return mAndromeda; 1867578d10f6cb2203ba3575b82b4b67e3a5d448bd7Yury Khmel } 1877578d10f6cb2203ba3575b82b4b67e3a5d448bd7Yury Khmel 1889dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel @Override 1899dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel public void onClick(View view) { 1909dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel if (view == mMeasureCompositionButton) { 1919dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel doTest(TEST_COMPOSITOR); 1929dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } else if (view == mMeasureAllocationButton) { 1939dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel doTest(TEST_ALLOCATION); 1949dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 1959dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 1969dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel 1979dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel private void doTest(final int test) { 1989dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel enableControls(false); 1999dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel final int pixelFormat = PIXEL_FORMATS[mPixelFormatSelector.getSelectedItemPosition()]; 2009dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel new Thread() { 2019dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel public void run() { 2029dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel final StringBuffer sb = new StringBuffer(); 2039dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel switch (test) { 2049dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel case TEST_COMPOSITOR: { 2059dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel sb.append("Compositor score:"); 2069dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel CompositorScore score = measureCompositionScore(pixelFormat); 2079dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel sb.append("\n " + getPixelFormatInfo(pixelFormat) + ":" + 2089dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel score + "."); 2099dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 2109dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel break; 2119dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel case TEST_ALLOCATION: { 2129dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel sb.append("Allocation score:"); 2139dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel AllocationScore score = measureAllocationScore(pixelFormat); 2149dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel sb.append("\n " + getPixelFormatInfo(pixelFormat) + ":" + 2159dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel score + "."); 2169dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 2179dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel break; 2189dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 2199dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel runOnUiThreadAndWait(new Runnable() { 2209dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel public void run() { 2219dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel mResultView.setText(sb.toString()); 2229dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel enableControls(true); 2239dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel updateSystemInfo(pixelFormat); 2249dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 2259dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel }); 2269dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 2279dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel }.start(); 2289dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 2299dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel 2309dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel /** 2319dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel * Wait until activity is resumed. 2329dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel */ 2339dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel public void waitForActivityResumed() { 2349dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel synchronized (mLockResumed) { 2359dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel if (!mResumed) { 2369dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel try { 2379dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel mLockResumed.wait(10000); 2389dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } catch (InterruptedException e) { 2399dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 2409dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 2419dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel if (!mResumed) { 2429dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel throw new RuntimeException("Activity was not resumed"); 2439dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 2449dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 2459dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 2469dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel 2479dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel @Override 2489dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel protected void onCreate(Bundle savedInstanceState) { 2499dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel super.onCreate(savedInstanceState); 2509dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel 2519dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); 2529dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel 2537578d10f6cb2203ba3575b82b4b67e3a5d448bd7Yury Khmel // Detect Andromeda devices by having free-form window management feature. 2547578d10f6cb2203ba3575b82b4b67e3a5d448bd7Yury Khmel mAndromeda = getPackageManager().hasSystemFeature( 2557578d10f6cb2203ba3575b82b4b67e3a5d448bd7Yury Khmel PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT); 2569dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel detectRefreshRate(); 2579dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel 2589dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel // To layouts in parent. First contains list of Surfaces and second 2599dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel // controls. Controls stay on top. 2609dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel RelativeLayout rootLayout = new RelativeLayout(this); 2619dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel rootLayout.setLayoutParams(new ViewGroup.LayoutParams( 2629dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel ViewGroup.LayoutParams.MATCH_PARENT, 2639dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel ViewGroup.LayoutParams.MATCH_PARENT)); 2649dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel 2659dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel CustomLayout layout = new CustomLayout(this); 2669dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel layout.setLayoutParams(new ViewGroup.LayoutParams( 2679dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel ViewGroup.LayoutParams.MATCH_PARENT, 2689dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel ViewGroup.LayoutParams.MATCH_PARENT)); 2699dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel 2709dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel Rect rect = new Rect(); 2719dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel getWindow().getDecorView().getWindowVisibleDisplayFrame(rect); 2729dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel mWidth = rect.right; 2739dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel mHeight = rect.bottom; 2749dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel long maxMemoryPerSurface = roundToNextPowerOf2(mWidth) * roundToNextPowerOf2(mHeight) * 4; 2759dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel // Use 75% of available memory. 2769dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel int surfaceCnt = (int)((getMemoryInfo().availMem * 3) / (4 * maxMemoryPerSurface)); 2779dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel if (surfaceCnt < MIN_NUMBER_OF_SURFACES) { 2789dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel throw new RuntimeException("Not enough memory to allocate " + 2799dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel MIN_NUMBER_OF_SURFACES + " surfaces."); 2809dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 2819dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel if (surfaceCnt > MAX_NUMBER_OF_SURFACES) { 2829dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel surfaceCnt = MAX_NUMBER_OF_SURFACES; 2839dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 2849dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel 2859dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel LinearLayout controlLayout = new LinearLayout(this); 2869dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel controlLayout.setOrientation(LinearLayout.VERTICAL); 2879dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel controlLayout.setLayoutParams(new ViewGroup.LayoutParams( 2889dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel ViewGroup.LayoutParams.MATCH_PARENT, 2899dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel ViewGroup.LayoutParams.MATCH_PARENT)); 2909dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel 2919dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel mMeasureCompositionButton = createButton("Compositor speed.", controlLayout); 2929dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel mMeasureAllocationButton = createButton("Allocation speed", controlLayout); 2939dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel 2949dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel String[] pixelFomats = new String[PIXEL_FORMATS.length]; 2959dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel for (int i = 0; i < pixelFomats.length; ++i) { 2969dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel pixelFomats[i] = getPixelFormatInfo(PIXEL_FORMATS[i]); 2979dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 2989dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel mPixelFormatSelector = new Spinner(this); 2999dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel ArrayAdapter<String> pixelFormatSelectorAdapter = 3009dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, pixelFomats); 3019dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel pixelFormatSelectorAdapter.setDropDownViewResource( 3029dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel android.R.layout.simple_spinner_dropdown_item); 3039dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel mPixelFormatSelector.setAdapter(pixelFormatSelectorAdapter); 3049dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel mPixelFormatSelector.setLayoutParams(new LinearLayout.LayoutParams( 3059dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel ViewGroup.LayoutParams.WRAP_CONTENT, 3069dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel ViewGroup.LayoutParams.WRAP_CONTENT)); 3079dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel controlLayout.addView(mPixelFormatSelector); 3089dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel 3099dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel mResultView = new TextView(this); 3109dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel mResultView.setBackgroundColor(0); 3119dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel mResultView.setText("Press button to start test."); 3129dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel mResultView.setLayoutParams(new LinearLayout.LayoutParams( 3139dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel ViewGroup.LayoutParams.WRAP_CONTENT, 3149dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel ViewGroup.LayoutParams.WRAP_CONTENT)); 3159dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel controlLayout.addView(mResultView); 3169dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel 3179dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel mSystemInfoView = new TextView(this); 3189dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel mSystemInfoView.setBackgroundColor(0); 3199dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel mSystemInfoView.setLayoutParams(new LinearLayout.LayoutParams( 3209dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel ViewGroup.LayoutParams.WRAP_CONTENT, 3219dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel ViewGroup.LayoutParams.WRAP_CONTENT)); 3229dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel controlLayout.addView(mSystemInfoView); 3239dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel 3249dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel for (int i = 0; i < surfaceCnt; ++i) { 3259dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel CustomSurfaceView view = new CustomSurfaceView(this, "Surface:" + i); 3269dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel // Create all surfaces overlapped in order to prevent SurfaceFlinger 3279dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel // to filter out surfaces by optimization in case surface is opaque. 3289dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel // In case surface is transparent it will be drawn anyway. Note that first 3299dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel // surface covers whole screen and must stand below other surfaces. Z order of 3309dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel // layers is not predictable and there is only one way to force first 3319dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel // layer to be below others is to mark it as media and all other layers 3329dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel // to mark as media overlay. 3339dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel if (i == 0) { 3349dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel view.setLayoutParams(new CustomLayout.LayoutParams(0, 0, mWidth, mHeight)); 3359dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel view.setZOrderMediaOverlay(false); 3369dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } else { 3379dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel // Z order of other layers is not predefined so make offset on x and reverse 3389dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel // offset on y to make sure that surface is visible in any layout. 3399dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel int x = i; 3409dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel int y = (surfaceCnt - i); 3419dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel view.setLayoutParams(new CustomLayout.LayoutParams(x, y, x + mWidth, y + mHeight)); 3429dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel view.setZOrderMediaOverlay(true); 3439dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 3449dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel view.setVisibility(View.INVISIBLE); 3459dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel layout.addView(view); 3469dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel mViews.add(view); 3479dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 3489dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel 3499dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel rootLayout.addView(layout); 3509dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel rootLayout.addView(controlLayout); 3519dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel 3529dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel setContentView(rootLayout); 3539dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 3549dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel 3559dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel private Button createButton(String caption, LinearLayout layout) { 3569dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel Button button = new Button(this); 3579dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel button.setText(caption); 3589dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel button.setLayoutParams(new LinearLayout.LayoutParams( 3599dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel ViewGroup.LayoutParams.WRAP_CONTENT, 3609dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel ViewGroup.LayoutParams.WRAP_CONTENT)); 3619dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel button.setOnClickListener(this); 3629dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel layout.addView(button); 3639dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel return button; 3649dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 3659dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel 3669dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel private void enableControls(boolean enabled) { 3679dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel mMeasureCompositionButton.setEnabled(enabled); 3689dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel mMeasureAllocationButton.setEnabled(enabled); 3699dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel mPixelFormatSelector.setEnabled(enabled); 3709dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 3719dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel 3729dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel @Override 3739dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel protected void onResume() { 3749dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel super.onResume(); 3759dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel 3769dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel updateSystemInfo(PixelFormat.UNKNOWN); 3779dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel 3789dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel synchronized (mLockResumed) { 3799dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel mResumed = true; 3809dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel mLockResumed.notifyAll(); 3819dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 3829dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 3839dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel 3849dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel @Override 3859dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel protected void onPause() { 3869dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel super.onPause(); 3879dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel 3889dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel synchronized (mLockResumed) { 3899dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel mResumed = false; 3909dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 3919dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 3929dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel 3939dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel class Measurement { 3949dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel Measurement(int surfaceCnt, double fps) { 3959dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel mSurfaceCnt = surfaceCnt; 3969dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel mFPS = fps; 3979dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 3989dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel 3999dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel public final int mSurfaceCnt; 4009dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel public final double mFPS; 4019dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 4029dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel 4039dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel private double measureCompositionScore(Measurement ok, Measurement fail, int pixelFormat) { 4049dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel if (ok.mSurfaceCnt + 1 == fail.mSurfaceCnt) { 4059dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel // Interpolate result. 4069dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel double fraction = (mTargetFPS - fail.mFPS) / (ok.mFPS - fail.mFPS); 4079dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel return ok.mSurfaceCnt + fraction; 4089dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 4099dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel 4109dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel int medianSurfaceCnt = (ok.mSurfaceCnt + fail.mSurfaceCnt) / 2; 4119dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel Measurement median = new Measurement(medianSurfaceCnt, 4129dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel measureFPS(medianSurfaceCnt, pixelFormat)); 4139dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel 4149dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel if (median.mFPS >= mTargetFPS) { 4159dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel return measureCompositionScore(median, fail, pixelFormat); 4169dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } else { 4179dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel return measureCompositionScore(ok, median, pixelFormat); 4189dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 4199dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 4209dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel 4219dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel private double measureFPS(int surfaceCnt, int pixelFormat) { 4229dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel configureSurfacesAndWait(surfaceCnt, pixelFormat, true); 4239dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel // At least one view is visible and it is enough to update only 4249dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel // one overlapped surface in order to force SurfaceFlinger to send 4259dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel // all surfaces to compositor. 4269dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel double fps = mViews.get(0).measureFPS(mRefreshRate * 0.8, mRefreshRate * 0.999); 4279dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel 4289dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel // Make sure that surface configuration was not changed. 4299dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel validateSurfacesNotChanged(); 4309dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel 4319dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel return fps; 4329dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 4339dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel 4349dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel private void waitForSurfacesConfigured(final int pixelFormat) { 4359dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel for (int i = 0; i < mViews.size(); ++i) { 4369dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel CustomSurfaceView view = mViews.get(i); 4379dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel if (view.getVisibility() == View.VISIBLE) { 4389dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel view.waitForSurfaceReady(); 4399dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } else { 4409dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel view.waitForSurfaceDestroyed(); 4419dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 4429dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 4439dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel runOnUiThreadAndWait(new Runnable() { 4449dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel @Override 4459dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel public void run() { 4469dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel updateSystemInfo(pixelFormat); 4479dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 4489dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel }); 4499dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 4509dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel 4519dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel private void validateSurfacesNotChanged() { 4529dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel for (int i = 0; i < mViews.size(); ++i) { 4539dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel CustomSurfaceView view = mViews.get(i); 4549dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel view.validateSurfaceNotChanged(); 4559dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 4569dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 4579dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel 4589dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel private void configureSurfaces(int surfaceCnt, int pixelFormat, boolean invalidate) { 4599dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel for (int i = 0; i < mViews.size(); ++i) { 4609dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel CustomSurfaceView view = mViews.get(i); 4619dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel if (i < surfaceCnt) { 4629dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel view.setMode(pixelFormat, invalidate); 4639dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel view.setVisibility(View.VISIBLE); 4649dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } else { 4659dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel view.setVisibility(View.INVISIBLE); 4669dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 4679dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 4689dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 4699dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel 4709dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel private void configureSurfacesAndWait(final int surfaceCnt, final int pixelFormat, 4719dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel final boolean invalidate) { 4729dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel runOnUiThreadAndWait(new Runnable() { 4739dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel @Override 4749dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel public void run() { 4759dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel configureSurfaces(surfaceCnt, pixelFormat, invalidate); 4769dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 4779dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel }); 4789dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel waitForSurfacesConfigured(pixelFormat); 4799dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 4809dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel 4819dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel private void acquireSurfacesCanvas() { 4829dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel for (int i = 0; i < mViews.size(); ++i) { 4839dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel CustomSurfaceView view = mViews.get(i); 4849dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel view.acquireCanvas(); 4859dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 4869dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 4879dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel 4889dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel private void releaseSurfacesCanvas() { 4899dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel for (int i = 0; i < mViews.size(); ++i) { 4909dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel CustomSurfaceView view = mViews.get(i); 4919dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel view.releaseCanvas(); 4929dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 4939dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 4949dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel 4959dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel private static String getReadableMemory(long bytes) { 4969dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel long unit = 1024; 4979dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel if (bytes < unit) { 4989dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel return bytes + " B"; 4999dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 5009dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel int exp = (int) (Math.log(bytes) / Math.log(unit)); 5019dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel return String.format("%.1f %sB", bytes / Math.pow(unit, exp), 5029dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel "KMGTPE".charAt(exp-1)); 5039dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 5049dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel 5059dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel private MemoryInfo getMemoryInfo() { 5069dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel ActivityManager activityManager = (ActivityManager) 5079dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel getSystemService(ACTIVITY_SERVICE); 5089dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel MemoryInfo memInfo = new MemoryInfo(); 5099dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel activityManager.getMemoryInfo(memInfo); 5109dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel return memInfo; 5119dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 5129dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel 5139dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel private void updateSystemInfo(int pixelFormat) { 5149dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel int visibleCnt = 0; 5159dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel for (int i = 0; i < mViews.size(); ++i) { 5169dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel if (mViews.get(i).getVisibility() == View.VISIBLE) { 5179dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel ++visibleCnt; 5189dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 5199dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 5209dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel 5219dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel MemoryInfo memInfo = getMemoryInfo(); 5227578d10f6cb2203ba3575b82b4b67e3a5d448bd7Yury Khmel String platformName = mAndromeda ? "Andromeda" : "Android"; 5237578d10f6cb2203ba3575b82b4b67e3a5d448bd7Yury Khmel String info = platformName + ": available " + 5249dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel getReadableMemory(memInfo.availMem) + " from " + 5259dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel getReadableMemory(memInfo.totalMem) + ".\nVisible " + 5269dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel visibleCnt + " from " + mViews.size() + " " + 5279dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel getPixelFormatInfo(pixelFormat) + " surfaces.\n" + 5289dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel "View size: " + mWidth + "x" + mHeight + 5299dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel ". Refresh rate: " + DOUBLE_FORMAT.format(mRefreshRate) + "."; 5309dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel mSystemInfoView.setText(info); 5319dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 5329dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel 5339dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel private void detectRefreshRate() { 5349dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel WindowManager wm = (WindowManager)getSystemService(Context.WINDOW_SERVICE); 5359dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel mRefreshRate = wm.getDefaultDisplay().getRefreshRate(); 5369dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel if (mRefreshRate < MIN_REFRESH_RATE_SUPPORTED) 5379dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel throw new RuntimeException("Unsupported display refresh rate: " + mRefreshRate); 5389dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel mTargetFPS = mRefreshRate - 2.0f; 5399dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 5409dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel 5419dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel private int roundToNextPowerOf2(int value) { 5429dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel --value; 5439dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel value |= value >> 1; 5449dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel value |= value >> 2; 5459dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel value |= value >> 4; 5469dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel value |= value >> 8; 5479dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel value |= value >> 16; 5489dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel return value + 1; 5499dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 5509dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel 5519dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel public static String getPixelFormatInfo(int pixelFormat) { 5529dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel switch (pixelFormat) { 5539dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel case PixelFormat.TRANSLUCENT: 5549dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel return "TRANSLUCENT"; 5559dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel case PixelFormat.TRANSPARENT: 5569dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel return "TRANSPARENT"; 5579dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel case PixelFormat.OPAQUE: 5589dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel return "OPAQUE"; 5599dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel case PixelFormat.RGBA_8888: 5609dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel return "RGBA_8888"; 5619dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel case PixelFormat.RGBX_8888: 5629dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel return "RGBX_8888"; 5639dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel case PixelFormat.RGB_888: 5649dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel return "RGB_888"; 5659dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel case PixelFormat.RGB_565: 5669dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel return "RGB_565"; 5679dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel default: 5689dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel return "PIX.FORMAT:" + pixelFormat; 5699dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 5709dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 5719dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel 5729dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel /** 5739dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel * A helper that executes a task in the UI thread and waits for its completion. 5749dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel * 5759dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel * @param task - task to execute. 5769dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel */ 5779dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel private void runOnUiThreadAndWait(Runnable task) { 5789dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel new UIExecutor(task); 5799dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 5809dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel 5819dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel class UIExecutor implements Runnable { 5829dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel private final Object mLock = new Object(); 5839dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel private Runnable mTask; 5849dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel private boolean mDone = false; 5859dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel 5869dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel UIExecutor(Runnable task) { 5879dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel mTask = task; 5889dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel mDone = false; 5899dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel runOnUiThread(this); 5909dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel synchronized (mLock) { 5919dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel while (!mDone) { 5929dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel try { 5939dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel mLock.wait(); 5949dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } catch (InterruptedException e) { 5959dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel e.printStackTrace(); 5969dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 5979dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 5989dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 5999dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 6009dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel 6019dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel public void run() { 6029dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel mTask.run(); 6039dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel synchronized (mLock) { 6049dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel mDone = true; 6059dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel mLock.notify(); 6069dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 6079dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 6089dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel } 6099dbde7b09f2366d2a239b1a4c234d5cf2de51739Yury Khmel} 610