1 /*
2  * Copyright (C) 2012 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 #define ATRACE_TAG ATRACE_TAG_ALWAYS
18 
19 #include <gui/Surface.h>
20 #include <gui/SurfaceControl.h>
21 #include <gui/GLConsumer.h>
22 #include <gui/Surface.h>
23 #include <gui/SurfaceComposerClient.h>
24 #include <ui/Fence.h>
25 #include <utils/Trace.h>
26 
27 #include <EGL/egl.h>
28 #include <GLES2/gl2.h>
29 
30 #include <math.h>
31 #include <getopt.h>
32 
33 #include "Flatland.h"
34 #include "GLHelper.h"
35 
36 using namespace ::android;
37 
38 static uint32_t    g_SleepBetweenSamplesMs = 0;
39 static bool        g_PresentToWindow       = false;
40 static size_t      g_BenchmarkNameLen      = 0;
41 static sp<IBinder> g_DisplayToken          = nullptr;
42 
43 struct BenchmarkDesc {
44     // The name of the test.
45     const char* name;
46 
47     // The dimensions of the space in which window layers are specified.
48     uint32_t width;
49     uint32_t height;
50 
51     // The screen heights at which to run the test.
52     uint32_t runHeights[MAX_TEST_RUNS];
53 
54     // The list of window layers.
55     LayerDesc layers[MAX_NUM_LAYERS];
56 };
57 
58 static const BenchmarkDesc benchmarks[] = {
59     { "16:10 Single Static Window",
60         2560, 1600, { 800, 1200, 1600, 2400 },
61         {
62             {   // Window
63                 0, staticGradient, opaque,
64                 0,    50,     2560,   1454,
65             },
66             {   // Status bar
67                 0, staticGradient, opaque,
68                 0,    0,      2560,   50,
69             },
70             {   // Navigation bar
71                 0, staticGradient, opaque,
72                 0,    1504,   2560,   96,
73             },
74         },
75     },
76 
77     { "4:3 Single Static Window",
78         2048, 1536, { 1536 },
79         {
80             {   // Window
81                 0, staticGradient, opaque,
82                 0,    50,     2048,   1440,
83             },
84             {   // Status bar
85                 0, staticGradient, opaque,
86                 0,    0,      2048,   50,
87             },
88             {   // Navigation bar
89                 0, staticGradient, opaque,
90                 0,    1440,   2048,   96,
91             },
92         },
93     },
94 
95     { "16:10 App -> Home Transition",
96         2560, 1600, { 800, 1200, 1600, 2400 },
97         {
98             {   // Wallpaper
99                 0, staticGradient, opaque,
100                 0,    50,     2560,   1454,
101             },
102             {   // Launcher
103                 0, staticGradient, blend,
104                 0,    50,     2560,   1454,
105             },
106             {   // Outgoing activity
107                 0, staticGradient, blendShrink,
108                 20,    70,     2520,   1414,
109             },
110             {   // Status bar
111                 0, staticGradient, opaque,
112                 0,    0,      2560,   50,
113             },
114             {   // Navigation bar
115                 0, staticGradient, opaque,
116                 0,    1504,   2560,   96,
117             },
118         },
119     },
120 
121     { "4:3 App -> Home Transition",
122         2048, 1536, { 1536 },
123         {
124             {   // Wallpaper
125                 0, staticGradient, opaque,
126                 0,    50,     2048,   1440,
127             },
128             {   // Launcher
129                 0, staticGradient, blend,
130                 0,    50,     2048,   1440,
131             },
132             {   // Outgoing activity
133                 0, staticGradient, blendShrink,
134                 20,    70,     2048,   1400,
135             },
136             {   // Status bar
137                 0, staticGradient, opaque,
138                 0,    0,      2048,   50,
139             },
140             {   // Navigation bar
141                 0, staticGradient, opaque,
142                 0,    1440,   2048,   96,
143             },
144         },
145     },
146 
147     { "16:10 SurfaceView -> Home Transition",
148         2560, 1600, { 800, 1200, 1600, 2400 },
149         {
150             {   // Wallpaper
151                 0, staticGradient, opaque,
152                 0,    50,     2560,   1454,
153             },
154             {   // Launcher
155                 0, staticGradient, blend,
156                 0,    50,     2560,   1454,
157             },
158             {   // Outgoing SurfaceView
159                 0, staticGradient, blendShrink,
160                 20,    70,     2520,   1414,
161             },
162             {   // Outgoing activity
163                 0, staticGradient, blendShrink,
164                 20,    70,     2520,   1414,
165             },
166             {   // Status bar
167                 0, staticGradient, opaque,
168                 0,    0,      2560,   50,
169             },
170             {   // Navigation bar
171                 0, staticGradient, opaque,
172                 0,    1504,   2560,   96,
173             },
174         },
175     },
176 
177     { "4:3 SurfaceView -> Home Transition",
178         2048, 1536, { 1536 },
179         {
180             {   // Wallpaper
181                 0, staticGradient, opaque,
182                 0,    50,     2048,   1440,
183             },
184             {   // Launcher
185                 0, staticGradient, blend,
186                 0,    50,     2048,   1440,
187             },
188             {   // Outgoing SurfaceView
189                 0, staticGradient, blendShrink,
190                 20,    70,     2048,   1400,
191             },
192             {   // Outgoing activity
193                 0, staticGradient, blendShrink,
194                 20,    70,     2048,   1400,
195             },
196             {   // Status bar
197                 0, staticGradient, opaque,
198                 0,    0,      2048,   50,
199             },
200             {   // Navigation bar
201                 0, staticGradient, opaque,
202                 0,    1440,   2048,   96,
203             },
204         },
205     },
206 };
207 
208 static const ShaderDesc shaders[] = {
209     {
210         .name="Blit",
211         .vertexShader={
212             "precision mediump float;",
213             "",
214             "attribute vec4 position;",
215             "attribute vec4 uv;",
216             "",
217             "varying vec4 texCoords;",
218             "",
219             "uniform mat4 objToNdc;",
220             "uniform mat4 uvToTex;",
221             "",
222             "void main() {",
223             "    gl_Position = objToNdc * position;",
224             "    texCoords = uvToTex * uv;",
225             "}",
226         },
227         .fragmentShader={
228             "#extension GL_OES_EGL_image_external : require",
229             "precision mediump float;",
230             "",
231             "varying vec4 texCoords;",
232             "",
233             "uniform samplerExternalOES blitSrc;",
234             "uniform vec4 modColor;",
235             "",
236             "void main() {",
237             "    gl_FragColor = texture2D(blitSrc, texCoords.xy);",
238             "    gl_FragColor *= modColor;",
239             "}",
240         },
241     },
242 
243     {
244         .name="Gradient",
245         .vertexShader={
246             "precision mediump float;",
247             "",
248             "attribute vec4 position;",
249             "attribute vec4 uv;",
250             "",
251             "varying float interp;",
252             "",
253             "uniform mat4 objToNdc;",
254             "uniform mat4 uvToInterp;",
255             "",
256             "void main() {",
257             "    gl_Position = objToNdc * position;",
258             "    interp = (uvToInterp * uv).x;",
259             "}",
260         },
261         .fragmentShader={
262             "precision mediump float;",
263             "",
264             "varying float interp;",
265             "",
266             "uniform vec4 color0;",
267             "uniform vec4 color1;",
268             "",
269             "uniform sampler2D ditherKernel;",
270             "uniform float invDitherKernelSize;",
271             "uniform float invDitherKernelSizeSq;",
272             "",
273             "void main() {",
274             "    float dither = texture2D(ditherKernel,",
275             "            gl_FragCoord.xy * invDitherKernelSize).a;",
276             "    dither *= invDitherKernelSizeSq;",
277             "    vec4 color = mix(color0, color1, clamp(interp, 0.0, 1.0));",
278             "    gl_FragColor = color + vec4(dither, dither, dither, 0.0);",
279             "}",
280         },
281     },
282 };
283 
284 class Layer {
285 
286 public:
287 
Layer()288     Layer() :
289         mGLHelper(nullptr),
290         mSurface(EGL_NO_SURFACE) {
291     }
292 
setUp(const LayerDesc & desc,GLHelper * helper)293     bool setUp(const LayerDesc& desc, GLHelper* helper) {
294         bool result;
295 
296         mDesc = desc;
297         mGLHelper = helper;
298 
299         result = mGLHelper->createSurfaceTexture(mDesc.width, mDesc.height,
300                 &mGLConsumer, &mSurface, &mTexName);
301         if (!result) {
302             return false;
303         }
304 
305         mRenderer = desc.rendererFactory();
306         result = mRenderer->setUp(helper);
307         if (!result) {
308             return false;
309         }
310 
311         mComposer = desc.composerFactory();
312         result = mComposer->setUp(desc, helper);
313         if (!result) {
314             return false;
315         }
316 
317         return true;
318     }
319 
tearDown()320     void tearDown() {
321         if (mComposer != nullptr) {
322             mComposer->tearDown();
323             delete mComposer;
324             mComposer = nullptr;
325         }
326 
327         if (mRenderer != nullptr) {
328             mRenderer->tearDown();
329             delete mRenderer;
330             mRenderer = nullptr;
331         }
332 
333         if (mSurface != EGL_NO_SURFACE) {
334             mGLHelper->destroySurface(&mSurface);
335             mGLConsumer->abandon();
336         }
337         mGLHelper = nullptr;
338         mGLConsumer.clear();
339     }
340 
render()341     bool render() {
342         return mRenderer->render(mSurface);
343     }
344 
prepareComposition()345     bool prepareComposition() {
346         status_t err;
347 
348         err = mGLConsumer->updateTexImage();
349         if (err < 0) {
350             fprintf(stderr, "GLConsumer::updateTexImage error: %d\n", err);
351             return false;
352         }
353 
354         return true;
355     }
356 
compose()357     bool compose() {
358         return mComposer->compose(mTexName, mGLConsumer);
359     }
360 
361 private:
362     LayerDesc mDesc;
363 
364     GLHelper* mGLHelper;
365 
366     GLuint mTexName;
367     sp<GLConsumer> mGLConsumer;
368     EGLSurface mSurface;
369 
370     Renderer* mRenderer;
371     Composer* mComposer;
372 };
373 
374 class BenchmarkRunner {
375 
376 public:
377 
BenchmarkRunner(const BenchmarkDesc & desc,size_t instance)378     BenchmarkRunner(const BenchmarkDesc& desc, size_t instance) :
379         mDesc(desc),
380         mInstance(instance),
381         mNumLayers(countLayers(desc)),
382         mGLHelper(nullptr),
383         mSurface(EGL_NO_SURFACE),
384         mWindowSurface(EGL_NO_SURFACE) {
385     }
386 
setUp()387     bool setUp() {
388         ATRACE_CALL();
389 
390         bool result;
391 
392         float scaleFactor = float(mDesc.runHeights[mInstance]) /
393             float(mDesc.height);
394         uint32_t w = uint32_t(scaleFactor * float(mDesc.width));
395         uint32_t h = mDesc.runHeights[mInstance];
396 
397         mGLHelper = new GLHelper();
398         result = mGLHelper->setUp(g_DisplayToken, shaders, NELEMS(shaders));
399         if (!result) {
400             return false;
401         }
402 
403         GLuint texName;
404         result = mGLHelper->createSurfaceTexture(w, h, &mGLConsumer, &mSurface,
405                 &texName);
406         if (!result) {
407             return false;
408         }
409 
410         for (size_t i = 0; i < mNumLayers; i++) {
411             // Scale the layer to match the current screen size.
412             LayerDesc ld = mDesc.layers[i];
413             ld.x = int32_t(scaleFactor * float(ld.x));
414             ld.y = int32_t(scaleFactor * float(ld.y));
415             ld.width = uint32_t(scaleFactor * float(ld.width));
416             ld.height = uint32_t(scaleFactor * float(ld.height));
417 
418             // Set up the layer.
419             result = mLayers[i].setUp(ld, mGLHelper);
420             if (!result) {
421                 return false;
422             }
423         }
424 
425         if (g_PresentToWindow) {
426             result = mGLHelper->createWindowSurface(w, h, &mSurfaceControl,
427                     &mWindowSurface);
428             if (!result) {
429                 return false;
430             }
431 
432             result = doFrame(mWindowSurface);
433             if (!result) {
434                 return false;
435             }
436         }
437 
438         return true;
439     }
440 
tearDown()441     void tearDown() {
442         ATRACE_CALL();
443 
444         for (size_t i = 0; i < mNumLayers; i++) {
445             mLayers[i].tearDown();
446         }
447 
448         if (mGLHelper != nullptr) {
449             if (mWindowSurface != EGL_NO_SURFACE) {
450                 mGLHelper->destroySurface(&mWindowSurface);
451             }
452             mGLHelper->destroySurface(&mSurface);
453             mGLConsumer->abandon();
454             mGLConsumer.clear();
455             mSurfaceControl.clear();
456             mGLHelper->tearDown();
457             delete mGLHelper;
458             mGLHelper = nullptr;
459         }
460     }
461 
run(uint32_t warmUpFrames,uint32_t totalFrames)462     nsecs_t run(uint32_t warmUpFrames, uint32_t totalFrames) {
463         ATRACE_CALL();
464 
465         bool result;
466 
467         resetColorGenerator();
468 
469         // Do the warm-up frames.
470         for (uint32_t i = 0; i < warmUpFrames; i++) {
471             result = doFrame(mSurface);
472             if (!result) {
473                 return -1;
474             }
475         }
476 
477         // Grab the fence for the start timestamp.
478         sp<Fence> startFence = mGLConsumer->getCurrentFence();
479 
480         //  the timed frames.
481         for (uint32_t i = warmUpFrames; i < totalFrames; i++) {
482             result = doFrame(mSurface);
483             if (!result) {
484                 return -1;
485             }
486         }
487 
488         // Grab the fence for the end timestamp.
489         sp<Fence> endFence = mGLConsumer->getCurrentFence();
490 
491         // Keep doing frames until the end fence has signaled.
492         while (endFence->wait(0) == -ETIME) {
493             result = doFrame(mSurface);
494             if (!result) {
495                 return -1;
496             }
497         }
498 
499         // Compute the time delta.
500         nsecs_t startTime = startFence->getSignalTime();
501         nsecs_t endTime = endFence->getSignalTime();
502 
503         return endTime - startTime;
504     }
505 
506 private:
507 
doFrame(EGLSurface surface)508     bool doFrame(EGLSurface surface) {
509         bool result;
510         status_t err;
511 
512         for (size_t i = 0; i < mNumLayers; i++) {
513             result = mLayers[i].render();
514             if (!result) {
515                 return false;
516             }
517         }
518 
519         for (size_t i = 0; i < mNumLayers; i++) {
520             result = mLayers[i].prepareComposition();
521             if (!result) {
522                 return false;
523             }
524         }
525 
526         result = mGLHelper->makeCurrent(surface);
527         if (!result) {
528             return false;
529         }
530 
531         glClearColor(1.0f, 0.0f, 0.0f, 0.0f);
532         glClear(GL_COLOR_BUFFER_BIT);
533 
534         for (size_t i = 0; i < mNumLayers; i++) {
535             result = mLayers[i].compose();
536             if (!result) {
537                 return false;
538             }
539         }
540 
541         result = mGLHelper->swapBuffers(surface);
542         if (!result) {
543             return false;
544         }
545 
546         err = mGLConsumer->updateTexImage();
547         if (err < 0) {
548             fprintf(stderr, "GLConsumer::updateTexImage error: %d\n", err);
549             return false;
550         }
551 
552         return true;
553     }
554 
countLayers(const BenchmarkDesc & desc)555     static size_t countLayers(const BenchmarkDesc& desc) {
556         size_t i;
557         for (i = 0; i < MAX_NUM_LAYERS; i++) {
558             if (desc.layers[i].rendererFactory == nullptr) {
559                 break;
560             }
561         }
562         return i;
563     }
564 
565     const BenchmarkDesc& mDesc;
566     const size_t mInstance;
567     const size_t mNumLayers;
568 
569     GLHelper* mGLHelper;
570 
571     // The surface into which layers are composited
572     sp<GLConsumer> mGLConsumer;
573     EGLSurface mSurface;
574 
575     // Used for displaying the surface to a window.
576     EGLSurface mWindowSurface;
577     sp<SurfaceControl> mSurfaceControl;
578 
579     Layer mLayers[MAX_NUM_LAYERS];
580 };
581 
cmpDouble(const double * lhs,const double * rhs)582 static int cmpDouble(const double* lhs, const double* rhs) {
583     if (*lhs < *rhs) {
584         return -1;
585     } else if (*rhs < *lhs) {
586         return 1;
587     }
588     return 0;
589 }
590 
591 // Run a single benchmark and print the result.
runTest(const BenchmarkDesc b,size_t run)592 static bool runTest(const BenchmarkDesc b, size_t run) {
593     bool success = true;
594     double prevResult = 0.0, result = 0.0;
595     Vector<double> samples;
596 
597     uint32_t runHeight = b.runHeights[run];
598     uint32_t runWidth = b.width * runHeight / b.height;
599     printf(" %-*s | %4d x %4d | ", static_cast<int>(g_BenchmarkNameLen), b.name,
600             runWidth, runHeight);
601     fflush(stdout);
602 
603     BenchmarkRunner r(b, run);
604     if (!r.setUp()) {
605         fprintf(stderr, "error initializing runner.\n");
606         return false;
607     }
608 
609     // The slowest 1/outlierFraction sample results are ignored as potential
610     // outliers.
611     const uint32_t outlierFraction = 16;
612     const double threshold = .0025;
613 
614     uint32_t warmUpFrames = 1;
615     uint32_t totalFrames = 5;
616 
617     // Find the number of frames needed to run for over 100ms.
618     double runTime = 0.0;
619     while (true) {
620         runTime = double(r.run(warmUpFrames, totalFrames));
621         if (runTime < 50e6) {
622             warmUpFrames *= 2;
623             totalFrames *= 2;
624         } else {
625             break;
626         }
627     }
628 
629 
630     if (totalFrames - warmUpFrames > 16) {
631         // The test runs too fast to get a stable result.  Skip it.
632         printf("  fast");
633         goto done;
634     } else if (totalFrames == 5 && runTime > 200e6) {
635         // The test runs too slow to be very useful.  Skip it.
636         printf("  slow");
637         goto done;
638     }
639 
640     do {
641         size_t newSamples = samples.size();
642         if (newSamples == 0) {
643             newSamples = 4*outlierFraction;
644         }
645 
646         if (newSamples > 512) {
647             printf("varies");
648             goto done;
649         }
650 
651         for (size_t i = 0; i < newSamples; i++) {
652             double sample = double(r.run(warmUpFrames, totalFrames));
653 
654             if (g_SleepBetweenSamplesMs > 0) {
655                 usleep(g_SleepBetweenSamplesMs  * 1000);
656             }
657 
658             if (sample < 0.0) {
659                 success = false;
660                 goto done;
661             }
662 
663             samples.add(sample);
664         }
665 
666         samples.sort(cmpDouble);
667 
668         prevResult = result;
669         size_t elem = (samples.size() * (outlierFraction-1) / outlierFraction);
670         result = (samples[elem-1] + samples[elem]) * 0.5;
671     } while (fabs(result - prevResult) > threshold * result);
672 
673     printf("%6.3f", result / double(totalFrames - warmUpFrames) / 1e6);
674 
675 done:
676 
677     printf("\n");
678     fflush(stdout);
679     r.tearDown();
680 
681     return success;
682 }
683 
printResultsTableHeader()684 static void printResultsTableHeader() {
685     const char* scenario = "Scenario";
686     size_t len = strlen(scenario);
687     size_t leftPad = (g_BenchmarkNameLen - len) / 2;
688     size_t rightPad = g_BenchmarkNameLen - len - leftPad;
689     printf(" %*s%s%*s | Resolution  | Time (ms)\n",
690             static_cast<int>(leftPad), "",
691             "Scenario", static_cast<int>(rightPad), "");
692 }
693 
694 // Run ALL the benchmarks!
runTests()695 static bool runTests() {
696     printResultsTableHeader();
697 
698     for (size_t i = 0; i < NELEMS(benchmarks); i++) {
699         const BenchmarkDesc& b = benchmarks[i];
700         for (size_t j = 0; j < MAX_TEST_RUNS && b.runHeights[j]; j++) {
701             if (!runTest(b, j)) {
702                 return false;
703             }
704         }
705     }
706     return true;
707 }
708 
709 // Return the length longest benchmark name.
maxBenchmarkNameLen()710 static size_t maxBenchmarkNameLen() {
711     size_t maxLen = 0;
712     for (size_t i = 0; i < NELEMS(benchmarks); i++) {
713         const BenchmarkDesc& b = benchmarks[i];
714         size_t len = strlen(b.name);
715         if (len > maxLen) {
716             maxLen = len;
717         }
718     }
719     return maxLen;
720 }
721 
722 // Print the command usage help to stderr.
showHelp(const char * cmd)723 static void showHelp(const char* cmd) {
724   fprintf(stderr, "usage: %s [options]\n", cmd);
725   fprintf(
726       stderr,
727       "options include:\n"
728       "  -s N            sleep for N ms between samples\n"
729       "  -d              display the test frame to a window\n"
730       "  -i display-id   specify a display ID to use for multi-display device\n"
731       "                  see \"dumpsys SurfaceFlinger --display-id\" for valid "
732       "display IDs\n"
733       "  --help          print this helpful message and exit\n");
734 }
735 
main(int argc,char ** argv)736 int main(int argc, char** argv) {
737     if (argc == 2 && 0 == strcmp(argv[1], "--help")) {
738         showHelp(argv[0]);
739         exit(0);
740     }
741 
742     const auto ids = SurfaceComposerClient::getPhysicalDisplayIds();
743     if (ids.empty()) {
744         fprintf(stderr, "Failed to get ID for any displays.\n");
745         exit(3);
746     }
747 
748     std::optional<PhysicalDisplayId> displayId;
749 
750     for (;;) {
751         int ret;
752         int option_index = 0;
753         static struct option long_options[] = {
754             {"help",     no_argument, 0,  0 },
755             {     0,               0, 0,  0 }
756         };
757 
758         ret = getopt_long(argc, argv, "ds:i:",
759                           long_options, &option_index);
760 
761         if (ret < 0) {
762             break;
763         }
764 
765         switch(ret) {
766             case 'd':
767                 g_PresentToWindow = true;
768             break;
769 
770             case 's':
771                 g_SleepBetweenSamplesMs = atoi(optarg);
772             break;
773 
774             case 'i':
775                 displayId = DisplayId::fromValue<PhysicalDisplayId>(atoll(optarg));
776                 if (!displayId) {
777                     fprintf(stderr, "Invalid display ID: %s.\n", optarg);
778                     exit(4);
779                 }
780             break;
781 
782             case 0:
783                 if (strcmp(long_options[option_index].name, "help")) {
784                     showHelp(argv[0]);
785                     exit(0);
786                 }
787             break;
788 
789             default:
790                 showHelp(argv[0]);
791                 exit(2);
792         }
793     }
794 
795     if (!displayId) { // no display id is specified
796         if (ids.size() == 1) {
797             displayId = ids.front();
798         } else {
799             fprintf(stderr, "Please specify a display ID for multi-display device.\n");
800             showHelp(argv[0]);
801             exit(5);
802         }
803     }
804 
805     g_DisplayToken = SurfaceComposerClient::getPhysicalDisplayToken(*displayId);
806     if (g_DisplayToken == nullptr) {
807         fprintf(stderr, "SurfaceComposer::getPhysicalDisplayToken failed.\n");
808         exit(6);
809     }
810 
811     g_BenchmarkNameLen = maxBenchmarkNameLen();
812 
813     printf(" cmdline:");
814     for (int i = 0; i < argc; i++) {
815         printf(" %s", argv[i]);
816     }
817     printf("\n");
818 
819     if (!runTests()) {
820         fprintf(stderr, "exiting due to error.\n");
821         return 1;
822     }
823 
824     return 0;
825 }
826