1 /*
2  * Copyright (C) 2022 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 
17 package android.surfaceflinger;
18 
19 import android.graphics.Bitmap;
20 import android.graphics.Canvas;
21 import android.graphics.Color;
22 import android.os.Bundle;
23 import android.util.Log;
24 import android.view.SurfaceControl;
25 import android.view.SurfaceHolder;
26 import android.view.SurfaceView;
27 
28 
29 import androidx.test.ext.junit.rules.ActivityScenarioRule;
30 import androidx.test.filters.LargeTest;
31 import androidx.test.platform.app.InstrumentationRegistry;
32 import androidx.test.runner.AndroidJUnit4;
33 
34 import org.junit.After;
35 import org.junit.Before;
36 import org.junit.BeforeClass;
37 import org.junit.Rule;
38 import org.junit.Test;
39 import org.junit.rules.RuleChain;
40 import org.junit.runner.RunWith;
41 
42 import java.util.ArrayList;
43 import java.util.Random;
44 
45 @LargeTest
46 @RunWith(AndroidJUnit4.class)
47 public class SurfaceFlingerPerfTest {
48     private static final String TAG = "SurfaceFlingerPerfTest";
49     private final ActivityScenarioRule<SurfaceFlingerTestActivity> mActivityRule =
50             new ActivityScenarioRule<>(SurfaceFlingerTestActivity.class);
51     private SurfaceFlingerTestActivity mActivity;
52     private static final int BUFFER_COUNT = 2;
53     private static final int MAX_BUFFERS = 10;
54     private static final int MAX_POSITION = 10;
55     private static final float MAX_SCALE = 2.0f;
56 
57     private static final String ARGUMENT_PROFILING_ITERATIONS = "profiling-iterations";
58     private static final String DEFAULT_PROFILING_ITERATIONS = "100";
59     private static int sProfilingIterations;
60     private final SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction();
61 
62     @Rule
63     public final RuleChain mAllRules = RuleChain
64             .outerRule(mActivityRule);
65 
66     @BeforeClass
suiteSetup()67     public static void suiteSetup() {
68         final Bundle arguments = InstrumentationRegistry.getArguments();
69         sProfilingIterations = Integer.parseInt(
70                 arguments.getString(ARGUMENT_PROFILING_ITERATIONS, DEFAULT_PROFILING_ITERATIONS));
71         Log.d(TAG, "suiteSetup: mProfilingIterations = " + sProfilingIterations);
72     }
73 
74     @Before
setup()75     public void setup() {
76         mActivityRule.getScenario().onActivity(activity -> mActivity = activity);
77         SurfaceControl.Transaction t = new SurfaceControl.Transaction();
78         for (int i = 0; i < MAX_BUFFERS; i++) {
79             SurfaceControl sc = createSurfaceControl();
80             BufferFlinger bufferTracker = createBufferTracker(Color.argb(getRandomColorComponent(),
81                     getRandomColorComponent(), getRandomColorComponent(),
82                     getRandomColorComponent()));
83             bufferTracker.addBuffer(t, sc);
84             t.setPosition(sc, i * 10, i * 10);
85         }
86         t.apply(true);
87     }
88 
89     @After
teardown()90     public void teardown() {
91         mSurfaceControls.forEach(SurfaceControl::release);
92         mBufferTrackers.forEach(BufferFlinger::freeBuffers);
93     }
94 
getRandomColorComponent()95     static int getRandomColorComponent() {
96         return new Random().nextInt(155) + 100;
97     }
98 
99     private final ArrayList<BufferFlinger> mBufferTrackers = new ArrayList<>();
createBufferTracker(int color)100     private BufferFlinger createBufferTracker(int color) {
101         BufferFlinger bufferTracker = new BufferFlinger(BUFFER_COUNT, color);
102         mBufferTrackers.add(bufferTracker);
103         return bufferTracker;
104     }
105 
106     private final ArrayList<SurfaceControl> mSurfaceControls = new ArrayList<>();
createSurfaceControl()107     private SurfaceControl createSurfaceControl() {
108         SurfaceControl sc = mActivity.createChildSurfaceControl();
109         mSurfaceControls.add(sc);
110         return sc;
111     }
112 
113     @Test
singleBuffer()114     public void singleBuffer() throws Exception {
115         for (int i = 0; i < sProfilingIterations; i++) {
116             mBufferTrackers.get(0).addBuffer(mTransaction, mSurfaceControls.get(0));
117             mTransaction.show(mSurfaceControls.get(0)).apply(true);
118         }
119     }
120 
121     @Test
multipleBuffers()122     public void multipleBuffers() throws Exception {
123         for (int j = 0; j < sProfilingIterations; j++) {
124             for (int i = 0; i < MAX_BUFFERS; i++) {
125                 mBufferTrackers.get(i).addBuffer(mTransaction, mSurfaceControls.get(i));
126                 mTransaction.show(mSurfaceControls.get(i));
127             }
128             mTransaction.apply(true);
129         }
130     }
131 
132     @Test
multipleOpaqueBuffers()133     public void multipleOpaqueBuffers() throws Exception {
134         for (int j = 0; j < sProfilingIterations; j++) {
135             for (int i = 0; i < MAX_BUFFERS; i++) {
136                 mBufferTrackers.get(i).addBuffer(mTransaction, mSurfaceControls.get(i));
137                 mTransaction.show(mSurfaceControls.get(i)).setOpaque(mSurfaceControls.get(i), true);
138             }
139             mTransaction.apply(true);
140         }
141     }
142 
143     @Test
geometryChanges()144     public void geometryChanges() throws Exception {
145         int step = 0;
146         for (int i = 0; i < sProfilingIterations; i++) {
147             step = ++step % MAX_POSITION;
148             mTransaction.setPosition(mSurfaceControls.get(0), step, step);
149             float scale = ((step * MAX_SCALE) / MAX_POSITION) + 0.5f;
150             mTransaction.setScale(mSurfaceControls.get(0), scale, scale);
151             mTransaction.show(mSurfaceControls.get(0)).apply(true);
152         }
153     }
154 
155     @Test
geometryWithBufferChanges()156     public void geometryWithBufferChanges() throws Exception {
157         int step = 0;
158         for (int i = 0; i < sProfilingIterations; i++) {
159             step = ++step % MAX_POSITION;
160             mTransaction.setPosition(mSurfaceControls.get(0), step, step);
161             float scale = ((step * MAX_SCALE) / MAX_POSITION) + 0.5f;
162             mTransaction.setScale(mSurfaceControls.get(0), scale, scale);
163             mBufferTrackers.get(0).addBuffer(mTransaction, mSurfaceControls.get(0));
164             mTransaction.show(mSurfaceControls.get(0)).apply(true);
165         }
166     }
167 
168     @Test
addRemoveLayers()169     public void addRemoveLayers() throws Exception {
170         for (int i = 0; i < sProfilingIterations; i++) {
171             SurfaceControl childSurfaceControl =  new SurfaceControl.Builder()
172                     .setName("childLayer").setBLASTLayer().build();
173             mBufferTrackers.get(0).addBuffer(mTransaction, childSurfaceControl);
174             mTransaction.reparent(childSurfaceControl, mSurfaceControls.get(0));
175             mTransaction.show(childSurfaceControl).show(mSurfaceControls.get(0));
176             mTransaction.apply(true);
177             mTransaction.remove(childSurfaceControl).apply(true);
178         }
179     }
180 
181     @Test
displayScreenshot()182     public void displayScreenshot() throws Exception {
183         for (int i = 0; i < sProfilingIterations; i++) {
184             Bitmap screenshot =
185                     InstrumentationRegistry.getInstrumentation().getUiAutomation().takeScreenshot();
186             screenshot.recycle();
187             mTransaction.apply(true);
188         }
189     }
190 
191     @Test
layerScreenshot()192     public void layerScreenshot() throws Exception {
193         for (int i = 0; i < sProfilingIterations; i++) {
194             Bitmap screenshot =
195                     InstrumentationRegistry.getInstrumentation().getUiAutomation().takeScreenshot(
196                             mActivity.getWindow());
197             screenshot.recycle();
198             mTransaction.apply(true);
199         }
200     }
201 
202     @Test
bufferQueue()203     public void bufferQueue() throws Exception {
204         SurfaceView testSV = mActivity.mTestSurfaceView;
205         SurfaceHolder holder = testSV.getHolder();
206         holder.getSurface();
207         for (int i = 0; i < sProfilingIterations; i++) {
208             Canvas canvas = holder.lockCanvas();
209             holder.unlockCanvasAndPost(canvas);
210             mTransaction.apply(true);
211         }
212     }
213 }
214