Home | History | Annotate | Download | only in hwc
      1 /*
      2  * Copyright (C) 2010 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 
     18 /*
     19  * Hardware Composer stress test
     20  *
     21  * Performs a pseudo-random (prandom) sequence of operations to the
     22  * Hardware Composer (HWC), for a specified number of passes or for
     23  * a specified period of time.  By default the period of time is FLT_MAX,
     24  * so that the number of passes will take precedence.
     25  *
     26  * The passes are grouped together, where (pass / passesPerGroup) specifies
     27  * which group a particular pass is in.  This causes every passesPerGroup
     28  * worth of sequential passes to be within the same group.  Computationally
     29  * intensive operations are performed just once at the beginning of a group
     30  * of passes and then used by all the passes in that group.  This is done
     31  * so as to increase both the average and peak rate of graphic operations,
     32  * by moving computationally intensive operations to the beginning of a group.
     33  * In particular, at the start of each group of passes a set of
     34  * graphic buffers are created, then used by the first and remaining
     35  * passes of that group of passes.
     36  *
     37  * The per-group initialization of the graphic buffers is performed
     38  * by a function called initFrames.  This function creates an array
     39  * of smart pointers to the graphic buffers, in the form of a vector
     40  * of vectors.  The array is accessed in row major order, so each
     41  * row is a vector of smart pointers.  All the pointers of a single
     42  * row point to graphic buffers which use the same pixel format and
     43  * have the same dimension, although it is likely that each one is
     44  * filled with a different color.  This is done so that after doing
     45  * the first HWC prepare then set call, subsequent set calls can
     46  * be made with each of the layer handles changed to a different
     47  * graphic buffer within the same row.  Since the graphic buffers
     48  * in a particular row have the same pixel format and dimension,
     49  * additional HWC set calls can be made, without having to perform
     50  * an HWC prepare call.
     51  *
     52  * This test supports the following command-line options:
     53  *
     54  *   -v        Verbose
     55  *   -s num    Starting pass
     56  *   -e num    Ending pass
     57  *   -p num    Execute the single pass specified by num
     58  *   -n num    Number of set operations to perform after each prepare operation
     59  *   -t float  Maximum time in seconds to execute the test
     60  *   -d float  Delay in seconds performed after each set operation
     61  *   -D float  Delay in seconds performed after the last pass is executed
     62  *
     63  * Typically the test is executed for a large range of passes.  By default
     64  * passes 0 through 99999 (100,000 passes) are executed.  Although this test
     65  * does not validate the generated image, at times it is useful to reexecute
     66  * a particular pass and leave the displayed image on the screen for an
     67  * extended period of time.  This can be done either by setting the -s
     68  * and -e options to the desired pass, along with a large value for -D.
     69  * This can also be done via the -p option, again with a large value for
     70  * the -D options.
     71  *
     72  * So far this test only contains code to create graphic buffers with
     73  * a continuous solid color.  Although this test is unable to validate the
     74  * image produced, any image that contains other than rectangles of a solid
     75  * color are incorrect.  Note that the rectangles may use a transparent
     76  * color and have a blending operation that causes the color in overlapping
     77  * rectangles to be mixed.  In such cases the overlapping portions may have
     78  * a different color from the rest of the rectangle.
     79  */
     80 
     81 #define LOG_TAG "hwcStressTest"
     82 
     83 #include <algorithm>
     84 #include <assert.h>
     85 #include <cerrno>
     86 #include <cmath>
     87 #include <cstdlib>
     88 #include <ctime>
     89 #include <libgen.h>
     90 #include <sched.h>
     91 #include <sstream>
     92 #include <stdint.h>
     93 #include <string.h>
     94 #include <unistd.h>
     95 #include <vector>
     96 
     97 #include <sys/syscall.h>
     98 #include <sys/types.h>
     99 #include <sys/wait.h>
    100 
    101 #include <EGL/egl.h>
    102 #include <EGL/eglext.h>
    103 #include <GLES2/gl2.h>
    104 #include <GLES2/gl2ext.h>
    105 
    106 #include <ui/GraphicBuffer.h>
    107 
    108 #include <utils/Log.h>
    109 #include <testUtil.h>
    110 
    111 #include <hardware/hwcomposer.h>
    112 
    113 #include <glTestLib.h>
    114 #include "hwcTestLib.h"
    115 
    116 using namespace std;
    117 using namespace android;
    118 
    119 const float maxSizeRatio = 1.3;  // Graphic buffers can be upto this munch
    120                                  // larger than the default screen size
    121 const unsigned int passesPerGroup = 10; // A group of passes all use the same
    122                                         // graphic buffers
    123 
    124 // Ratios at which rare and frequent conditions should be produced
    125 const float rareRatio = 0.1;
    126 const float freqRatio = 0.9;
    127 
    128 // Defaults for command-line options
    129 const bool defaultVerbose = false;
    130 const unsigned int defaultStartPass = 0;
    131 const unsigned int defaultEndPass = 99999;
    132 const unsigned int defaultPerPassNumSet = 10;
    133 const float defaultPerSetDelay = 0.0; // Default delay after each set
    134                                       // operation.  Default delay of
    135                                       // zero used so as to perform the
    136                                       // the set operations as quickly
    137                                       // as possible.
    138 const float defaultEndDelay = 2.0; // Default delay between completion of
    139                                    // final pass and restart of framework
    140 const float defaultDuration = FLT_MAX; // A fairly long time, so that
    141                                        // range of passes will have
    142                                        // precedence
    143 
    144 // Command-line option settings
    145 static bool verbose = defaultVerbose;
    146 static unsigned int startPass = defaultStartPass;
    147 static unsigned int endPass = defaultEndPass;
    148 static unsigned int numSet = defaultPerPassNumSet;
    149 static float perSetDelay = defaultPerSetDelay;
    150 static float endDelay = defaultEndDelay;
    151 static float duration = defaultDuration;
    152 
    153 // Command-line mutual exclusion detection flags.
    154 // Corresponding flag set true once an option is used.
    155 bool eFlag, sFlag, pFlag;
    156 
    157 #define MAXSTR               100
    158 #define MAXCMD               200
    159 #define BITSPERBYTE            8 // TODO: Obtain from <values.h>, once
    160                                  // it has been added
    161 
    162 #define CMD_STOP_FRAMEWORK   "stop 2>&1"
    163 #define CMD_START_FRAMEWORK  "start 2>&1"
    164 
    165 #define NUMA(a) (sizeof(a) / sizeof(a [0]))
    166 #define MEMCLR(addr, size) do { \
    167         memset((addr), 0, (size)); \
    168     } while (0)
    169 
    170 // File scope constants
    171 const unsigned int blendingOps[] = {
    172     HWC_BLENDING_NONE,
    173     HWC_BLENDING_PREMULT,
    174     HWC_BLENDING_COVERAGE,
    175 };
    176 const unsigned int layerFlags[] = {
    177     HWC_SKIP_LAYER,
    178 };
    179 const vector<unsigned int> vecLayerFlags(layerFlags,
    180     layerFlags + NUMA(layerFlags));
    181 
    182 const unsigned int transformFlags[] = {
    183     HWC_TRANSFORM_FLIP_H,
    184     HWC_TRANSFORM_FLIP_V,
    185     HWC_TRANSFORM_ROT_90,
    186     // ROT_180 & ROT_270 intentionally not listed, because they
    187     // they are formed from combinations of the flags already listed.
    188 };
    189 const vector<unsigned int> vecTransformFlags(transformFlags,
    190     transformFlags + NUMA(transformFlags));
    191 
    192 // File scope globals
    193 static const int texUsage = GraphicBuffer::USAGE_HW_TEXTURE |
    194         GraphicBuffer::USAGE_SW_WRITE_RARELY;
    195 static hwc_composer_device_1_t *hwcDevice;
    196 static EGLDisplay dpy;
    197 static EGLSurface surface;
    198 static EGLint width, height;
    199 static vector <vector <sp<GraphicBuffer> > > frames;
    200 
    201 // File scope prototypes
    202 void init(void);
    203 void initFrames(unsigned int seed);
    204 template <class T> vector<T> vectorRandSelect(const vector<T>& vec, size_t num);
    205 template <class T> T vectorOr(const vector<T>& vec);
    206 
    207 /*
    208  * Main
    209  *
    210  * Performs the following high-level sequence of operations:
    211  *
    212  *   1. Command-line parsing
    213  *
    214  *   2. Initialization
    215  *
    216  *   3. For each pass:
    217  *
    218  *        a. If pass is first pass or in a different group from the
    219  *           previous pass, initialize the array of graphic buffers.
    220  *
    221  *        b. Create a HWC list with room to specify a prandomly
    222  *           selected number of layers.
    223  *
    224  *        c. Select a subset of the rows from the graphic buffer array,
    225  *           such that there is a unique row to be used for each
    226  *           of the layers in the HWC list.
    227  *
    228  *        d. Prandomly fill in the HWC list with handles
    229  *           selected from any of the columns of the selected row.
    230  *
    231  *        e. Pass the populated list to the HWC prepare call.
    232  *
    233  *        f. Pass the populated list to the HWC set call.
    234  *
    235  *        g. If additional set calls are to be made, then for each
    236  *           additional set call, select a new set of handles and
    237  *           perform the set call.
    238  */
    239 int
    240 main(int argc, char *argv[])
    241 {
    242     int rv, opt;
    243     char *chptr;
    244     unsigned int pass;
    245     char cmd[MAXCMD];
    246     struct timeval startTime, currentTime, delta;
    247 
    248     testSetLogCatTag(LOG_TAG);
    249 
    250     // Parse command line arguments
    251     while ((opt = getopt(argc, argv, "vp:d:D:n:s:e:t:?h")) != -1) {
    252         switch (opt) {
    253           case 'd': // Delay after each set operation
    254             perSetDelay = strtod(optarg, &chptr);
    255             if ((*chptr != '\0') || (perSetDelay < 0.0)) {
    256                 testPrintE("Invalid command-line specified per pass delay of: "
    257                            "%s", optarg);
    258                 exit(1);
    259             }
    260             break;
    261 
    262           case 'D': // End of test delay
    263                     // Delay between completion of final pass and restart
    264                     // of framework
    265             endDelay = strtod(optarg, &chptr);
    266             if ((*chptr != '\0') || (endDelay < 0.0)) {
    267                 testPrintE("Invalid command-line specified end of test delay "
    268                            "of: %s", optarg);
    269                 exit(2);
    270             }
    271             break;
    272 
    273           case 't': // Duration
    274             duration = strtod(optarg, &chptr);
    275             if ((*chptr != '\0') || (duration < 0.0)) {
    276                 testPrintE("Invalid command-line specified duration of: %s",
    277                            optarg);
    278                 exit(3);
    279             }
    280             break;
    281 
    282           case 'n': // Num set operations per pass
    283             numSet = strtoul(optarg, &chptr, 10);
    284             if (*chptr != '\0') {
    285                 testPrintE("Invalid command-line specified num set per pass "
    286                            "of: %s", optarg);
    287                 exit(4);
    288             }
    289             break;
    290 
    291           case 's': // Starting Pass
    292             sFlag = true;
    293             if (pFlag) {
    294                 testPrintE("Invalid combination of command-line options.");
    295                 testPrintE("  The -p option is mutually exclusive from the");
    296                 testPrintE("  -s and -e options.");
    297                 exit(5);
    298             }
    299             startPass = strtoul(optarg, &chptr, 10);
    300             if (*chptr != '\0') {
    301                 testPrintE("Invalid command-line specified starting pass "
    302                            "of: %s", optarg);
    303                 exit(6);
    304             }
    305             break;
    306 
    307           case 'e': // Ending Pass
    308             eFlag = true;
    309             if (pFlag) {
    310                 testPrintE("Invalid combination of command-line options.");
    311                 testPrintE("  The -p option is mutually exclusive from the");
    312                 testPrintE("  -s and -e options.");
    313                 exit(7);
    314             }
    315             endPass = strtoul(optarg, &chptr, 10);
    316             if (*chptr != '\0') {
    317                 testPrintE("Invalid command-line specified ending pass "
    318                            "of: %s", optarg);
    319                 exit(8);
    320             }
    321             break;
    322 
    323           case 'p': // Run a single specified pass
    324             pFlag = true;
    325             if (sFlag || eFlag) {
    326                 testPrintE("Invalid combination of command-line options.");
    327                 testPrintE("  The -p option is mutually exclusive from the");
    328                 testPrintE("  -s and -e options.");
    329                 exit(9);
    330             }
    331             startPass = endPass = strtoul(optarg, &chptr, 10);
    332             if (*chptr != '\0') {
    333                 testPrintE("Invalid command-line specified pass of: %s",
    334                            optarg);
    335                 exit(10);
    336             }
    337             break;
    338 
    339           case 'v': // Verbose
    340             verbose = true;
    341             break;
    342 
    343           case 'h': // Help
    344           case '?':
    345           default:
    346             testPrintE("  %s [options]", basename(argv[0]));
    347             testPrintE("    options:");
    348             testPrintE("      -p Execute specified pass");
    349             testPrintE("      -s Starting pass");
    350             testPrintE("      -e Ending pass");
    351             testPrintE("      -t Duration");
    352             testPrintE("      -d Delay after each set operation");
    353             testPrintE("      -D End of test delay");
    354             testPrintE("      -n Num set operations per pass");
    355             testPrintE("      -v Verbose");
    356             exit(((optopt == 0) || (optopt == '?')) ? 0 : 11);
    357         }
    358     }
    359     if (endPass < startPass) {
    360         testPrintE("Unexpected ending pass before starting pass");
    361         testPrintE("  startPass: %u endPass: %u", startPass, endPass);
    362         exit(12);
    363     }
    364     if (argc != optind) {
    365         testPrintE("Unexpected command-line postional argument");
    366         testPrintE("  %s [-s start_pass] [-e end_pass] [-t duration]",
    367             basename(argv[0]));
    368         exit(13);
    369     }
    370     testPrintI("duration: %g", duration);
    371     testPrintI("startPass: %u", startPass);
    372     testPrintI("endPass: %u", endPass);
    373     testPrintI("numSet: %u", numSet);
    374 
    375     // Stop framework
    376     rv = snprintf(cmd, sizeof(cmd), "%s", CMD_STOP_FRAMEWORK);
    377     if (rv >= (signed) sizeof(cmd) - 1) {
    378         testPrintE("Command too long for: %s", CMD_STOP_FRAMEWORK);
    379         exit(14);
    380     }
    381     testExecCmd(cmd);
    382     testDelay(1.0); // TODO - need means to query whether asyncronous stop
    383                     // framework operation has completed.  For now, just wait
    384                     // a long time.
    385 
    386     init();
    387 
    388     // For each pass
    389     gettimeofday(&startTime, NULL);
    390     for (pass = startPass; pass <= endPass; pass++) {
    391         // Stop if duration of work has already been performed
    392         gettimeofday(&currentTime, NULL);
    393         delta = tvDelta(&startTime, &currentTime);
    394         if (tv2double(&delta) > duration) { break; }
    395 
    396         // Regenerate a new set of test frames when this pass is
    397         // either the first pass or is in a different group then
    398         // the previous pass.  A group of passes are passes that
    399         // all have the same quotient when their pass number is
    400         // divided by passesPerGroup.
    401         if ((pass == startPass)
    402             || ((pass / passesPerGroup) != ((pass - 1) / passesPerGroup))) {
    403             initFrames(pass / passesPerGroup);
    404         }
    405 
    406         testPrintI("==== Starting pass: %u", pass);
    407 
    408         // Cause deterministic sequence of prandom numbers to be
    409         // generated for this pass.
    410         srand48(pass);
    411 
    412         hwc_display_contents_1_t *list;
    413         list = hwcTestCreateLayerList(testRandMod(frames.size()) + 1);
    414         if (list == NULL) {
    415             testPrintE("hwcTestCreateLayerList failed");
    416             exit(20);
    417         }
    418 
    419         // Prandomly select a subset of frames to be used by this pass.
    420         vector <vector <sp<GraphicBuffer> > > selectedFrames;
    421         selectedFrames = vectorRandSelect(frames, list->numHwLayers);
    422 
    423         // Any transform tends to create a layer that the hardware
    424         // composer is unable to support and thus has to leave for
    425         // SurfaceFlinger.  Place heavy bias on specifying no transforms.
    426         bool noTransform = testRandFract() > rareRatio;
    427 
    428         for (unsigned int n1 = 0; n1 < list->numHwLayers; n1++) {
    429             unsigned int idx = testRandMod(selectedFrames[n1].size());
    430             sp<GraphicBuffer> gBuf = selectedFrames[n1][idx];
    431             hwc_layer_1_t *layer = &list->hwLayers[n1];
    432             layer->handle = gBuf->handle;
    433 
    434             layer->blending = blendingOps[testRandMod(NUMA(blendingOps))];
    435             layer->flags = (testRandFract() > rareRatio) ? 0
    436                 : vectorOr(vectorRandSelect(vecLayerFlags,
    437                            testRandMod(vecLayerFlags.size() + 1)));
    438             layer->transform = (noTransform || testRandFract() > rareRatio) ? 0
    439                 : vectorOr(vectorRandSelect(vecTransformFlags,
    440                            testRandMod(vecTransformFlags.size() + 1)));
    441             layer->sourceCrop.left = testRandMod(gBuf->getWidth());
    442             layer->sourceCrop.top = testRandMod(gBuf->getHeight());
    443             layer->sourceCrop.right = layer->sourceCrop.left
    444                 + testRandMod(gBuf->getWidth() - layer->sourceCrop.left) + 1;
    445             layer->sourceCrop.bottom = layer->sourceCrop.top
    446                 + testRandMod(gBuf->getHeight() - layer->sourceCrop.top) + 1;
    447             layer->displayFrame.left = testRandMod(width);
    448             layer->displayFrame.top = testRandMod(height);
    449             layer->displayFrame.right = layer->displayFrame.left
    450                 + testRandMod(width - layer->displayFrame.left) + 1;
    451             layer->displayFrame.bottom = layer->displayFrame.top
    452                 + testRandMod(height - layer->displayFrame.top) + 1;
    453 
    454             // Increase the frequency that a scale factor of 1.0 from
    455             // the sourceCrop to displayFrame occurs.  This is the
    456             // most common scale factor used by applications and would
    457             // be rarely produced by this stress test without this
    458             // logic.
    459             if (testRandFract() <= freqRatio) {
    460                 // Only change to scale factor to 1.0 if both the
    461                 // width and height will fit.
    462                 int sourceWidth = layer->sourceCrop.right
    463                                   - layer->sourceCrop.left;
    464                 int sourceHeight = layer->sourceCrop.bottom
    465                                    - layer->sourceCrop.top;
    466                 if (((layer->displayFrame.left + sourceWidth) <= width)
    467                     && ((layer->displayFrame.top + sourceHeight) <= height)) {
    468                     layer->displayFrame.right = layer->displayFrame.left
    469                                                 + sourceWidth;
    470                     layer->displayFrame.bottom = layer->displayFrame.top
    471                                                  + sourceHeight;
    472                 }
    473             }
    474 
    475             layer->visibleRegionScreen.numRects = 1;
    476             layer->visibleRegionScreen.rects = &layer->displayFrame;
    477         }
    478 
    479         // Perform prepare operation
    480         if (verbose) { testPrintI("Prepare:"); hwcTestDisplayList(list); }
    481         hwcDevice->prepare(hwcDevice, 1, &list);
    482         if (verbose) {
    483             testPrintI("Post Prepare:");
    484             hwcTestDisplayListPrepareModifiable(list);
    485         }
    486 
    487         // Turn off the geometry changed flag
    488         list->flags &= ~HWC_GEOMETRY_CHANGED;
    489 
    490         // Perform the set operation(s)
    491         if (verbose) {testPrintI("Set:"); }
    492         for (unsigned int n1 = 0; n1 < numSet; n1++) {
    493             if (verbose) { hwcTestDisplayListHandles(list); }
    494             list->dpy = dpy;
    495             list->sur = surface;
    496             hwcDevice->set(hwcDevice, 1, &list);
    497 
    498             // Prandomly select a new set of handles
    499             for (unsigned int n1 = 0; n1 < list->numHwLayers; n1++) {
    500                 unsigned int idx = testRandMod(selectedFrames[n1].size());
    501                 sp<GraphicBuffer> gBuf = selectedFrames[n1][idx];
    502                 hwc_layer_1_t *layer = &list->hwLayers[n1];
    503                 layer->handle = (native_handle_t *) gBuf->handle;
    504             }
    505 
    506             testDelay(perSetDelay);
    507         }
    508 
    509         hwcTestFreeLayerList(list);
    510         testPrintI("==== Completed pass: %u", pass);
    511     }
    512 
    513     testDelay(endDelay);
    514 
    515     // Start framework
    516     rv = snprintf(cmd, sizeof(cmd), "%s", CMD_START_FRAMEWORK);
    517     if (rv >= (signed) sizeof(cmd) - 1) {
    518         testPrintE("Command too long for: %s", CMD_START_FRAMEWORK);
    519         exit(21);
    520     }
    521     testExecCmd(cmd);
    522 
    523     testPrintI("Successfully completed %u passes", pass - startPass);
    524 
    525     return 0;
    526 }
    527 
    528 void init(void)
    529 {
    530     srand48(0); // Defensively set pseudo random number generator.
    531                 // Should not need to set this, because a stress test
    532                 // sets the seed on each pass.  Defensively set it here
    533                 // so that future code that uses pseudo random numbers
    534                 // before the first pass will be deterministic.
    535 
    536     hwcTestInitDisplay(verbose, &dpy, &surface, &width, &height);
    537 
    538     hwcTestOpenHwc(&hwcDevice);
    539 }
    540 
    541 /*
    542  * Initialize Frames
    543  *
    544  * Creates an array of graphic buffers, within the global variable
    545  * named frames.  The graphic buffers are contained within a vector of
    546  * vectors.  All the graphic buffers in a particular row are of the same
    547  * format and dimension.  Each graphic buffer is uniformly filled with a
    548  * prandomly selected color.  It is likely that each buffer, even
    549  * in the same row, will be filled with a unique color.
    550  */
    551 void initFrames(unsigned int seed)
    552 {
    553     int rv;
    554     const size_t maxRows = 5;
    555     const size_t minCols = 2;  // Need at least double buffering
    556     const size_t maxCols = 4;  // One more than triple buffering
    557 
    558     if (verbose) { testPrintI("initFrames seed: %u", seed); }
    559     srand48(seed);
    560     size_t rows = testRandMod(maxRows) + 1;
    561 
    562     frames.clear();
    563     frames.resize(rows);
    564 
    565     for (unsigned int row = 0; row < rows; row++) {
    566         // All frames within a row have to have the same format and
    567         // dimensions.  Width and height need to be >= 1.
    568         unsigned int formatIdx = testRandMod(NUMA(hwcTestGraphicFormat));
    569         const struct hwcTestGraphicFormat *formatPtr
    570             = &hwcTestGraphicFormat[formatIdx];
    571         int format = formatPtr->format;
    572 
    573         // Pick width and height, which must be >= 1 and the size
    574         // mod the wMod/hMod value must be equal to 0.
    575         size_t w = (width * maxSizeRatio) * testRandFract();
    576         size_t h = (height * maxSizeRatio) * testRandFract();
    577         w = max(size_t(1u), w);
    578         h = max(size_t(1u), h);
    579         if ((w % formatPtr->wMod) != 0) {
    580             w += formatPtr->wMod - (w % formatPtr->wMod);
    581         }
    582         if ((h % formatPtr->hMod) != 0) {
    583             h += formatPtr->hMod - (h % formatPtr->hMod);
    584         }
    585         if (verbose) {
    586             testPrintI("  frame %u width: %u height: %u format: %u %s",
    587                        row, w, h, format, hwcTestGraphicFormat2str(format));
    588         }
    589 
    590         size_t cols = testRandMod((maxCols + 1) - minCols) + minCols;
    591         frames[row].resize(cols);
    592         for (unsigned int col = 0; col < cols; col++) {
    593             ColorFract color(testRandFract(), testRandFract(), testRandFract());
    594             float alpha = testRandFract();
    595 
    596             frames[row][col] = new GraphicBuffer(w, h, format, texUsage);
    597             if ((rv = frames[row][col]->initCheck()) != NO_ERROR) {
    598                 testPrintE("GraphicBuffer initCheck failed, rv: %i", rv);
    599                 testPrintE("  frame %u width: %u height: %u format: %u %s",
    600                            row, w, h, format, hwcTestGraphicFormat2str(format));
    601                 exit(80);
    602             }
    603 
    604             hwcTestFillColor(frames[row][col].get(), color, alpha);
    605             if (verbose) {
    606                 testPrintI("    buf: %p handle: %p color: %s alpha: %f",
    607                            frames[row][col].get(), frames[row][col]->handle,
    608                            string(color).c_str(), alpha);
    609             }
    610         }
    611     }
    612 }
    613 
    614 /*
    615  * Vector Random Select
    616  *
    617  * Prandomly selects and returns num elements from vec.
    618  */
    619 template <class T>
    620 vector<T> vectorRandSelect(const vector<T>& vec, size_t num)
    621 {
    622     vector<T> rv = vec;
    623 
    624     while (rv.size() > num) {
    625         rv.erase(rv.begin() + testRandMod(rv.size()));
    626     }
    627 
    628     return rv;
    629 }
    630 
    631 /*
    632  * Vector Or
    633  *
    634  * Or's togethen the values of each element of vec and returns the result.
    635  */
    636 template <class T>
    637 T vectorOr(const vector<T>& vec)
    638 {
    639     T rv = 0;
    640 
    641     for (size_t n1 = 0; n1 < vec.size(); n1++) {
    642         rv |= vec[n1];
    643     }
    644 
    645     return rv;
    646 }
    647