Home | History | Annotate | Download | only in flatland
      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 
    287     Layer() :
    288         mFirstFrame(true),
    289         mGLHelper(NULL),
    290         mSurface(EGL_NO_SURFACE) {
    291     }
    292 
    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 
    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 
    341     bool render() {
    342         return mRenderer->render(mSurface);
    343     }
    344 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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.
    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 
    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!
    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.
    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.
    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 
    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