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