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