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