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