blob: 35e53abfa77b80277d007bb5198b9a360d1f5f47 [file] [log] [blame]
Louis Huemiller365b2c62010-11-22 18:05:30 -08001/*
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 <arpa/inet.h> // For ntohl() and htonl()
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/FramebufferNativeWindow.h>
107#include <ui/GraphicBuffer.h>
108#include <ui/EGLUtils.h>
109
110#define LOG_TAG "hwcStressTest"
111#include <utils/Log.h>
112#include <testUtil.h>
113
114#include <hardware/hwcomposer.h>
115
116using namespace std;
117using namespace android;
118
119const float maxSizeRatio = 1.3; // Graphic buffers can be upto this munch
120 // larger than the default screen size
121const unsigned int passesPerGroup = 10; // A group of passes all use the same
122 // graphic buffers
Louis Huemillerb5265942010-12-12 23:05:31 -0800123
124// Ratios at which rare and frequent conditions should be produced
125const float rareRatio = 0.1;
126const float freqRatio = 0.9;
Louis Huemiller365b2c62010-11-22 18:05:30 -0800127
128// Defaults for command-line options
129const bool defaultVerbose = false;
130const unsigned int defaultStartPass = 0;
131const unsigned int defaultEndPass = 99999;
132const unsigned int defaultPerPassNumSet = 10;
Louis Huemillerb5265942010-12-12 23:05:31 -0800133const 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.
Louis Huemiller365b2c62010-11-22 18:05:30 -0800138const float defaultEndDelay = 2.0; // Default delay between completion of
139 // final pass and restart of framework
140const float defaultDuration = FLT_MAX; // A fairly long time, so that
141 // range of passes will have
142 // precedence
143
144// Command-line option settings
145static bool verbose = defaultVerbose;
146static unsigned int startPass = defaultStartPass;
147static unsigned int endPass = defaultEndPass;
148static unsigned int numSet = defaultPerPassNumSet;
Louis Huemillerb5265942010-12-12 23:05:31 -0800149static float perSetDelay = defaultPerSetDelay;
Louis Huemiller365b2c62010-11-22 18:05:30 -0800150static float endDelay = defaultEndDelay;
151static float duration = defaultDuration;
152
153// Command-line mutual exclusion detection flags.
154// Corresponding flag set true once an option is used.
155bool 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// Represent RGB color as fraction of color components.
171// Each of the color components are expected in the range [0.0, 1.0]
172class RGBColor {
173 public:
174 RGBColor(): _r(0.0), _g(0.0), _b(0.0) {};
175 RGBColor(float f): _r(f), _g(f), _b(f) {}; // Gray
176 RGBColor(float r, float g, float b): _r(r), _g(g), _b(b) {};
177 float r(void) const { return _r; }
178 float g(void) const { return _g; }
179 float b(void) const { return _b; }
180
181 private:
182 float _r;
183 float _g;
184 float _b;
185};
186
187// Represent YUV color as fraction of color components.
188// Each of the color components are expected in the range [0.0, 1.0]
189class YUVColor {
190 public:
191 YUVColor(): _y(0.0), _u(0.0), _v(0.0) {};
192 YUVColor(float f): _y(f), _u(0.0), _v(0.0) {}; // Gray
193 YUVColor(float y, float u, float v): _y(y), _u(u), _v(v) {};
194 float y(void) const { return _y; }
195 float u(void) const { return _u; }
196 float v(void) const { return _v; }
197
198 private:
199 float _y;
200 float _u;
201 float _v;
202};
203
204// File scope constants
205static const struct {
206 unsigned int format;
207 const char *desc;
208} graphicFormat[] = {
209 {HAL_PIXEL_FORMAT_RGBA_8888, "RGBA8888"},
210 {HAL_PIXEL_FORMAT_RGBX_8888, "RGBX8888"},
Louis Huemillerb5265942010-12-12 23:05:31 -0800211 {HAL_PIXEL_FORMAT_RGB_888, "RGB888"},
Louis Huemiller365b2c62010-11-22 18:05:30 -0800212 {HAL_PIXEL_FORMAT_RGB_565, "RGB565"},
213 {HAL_PIXEL_FORMAT_BGRA_8888, "BGRA8888"},
214 {HAL_PIXEL_FORMAT_RGBA_5551, "RGBA5551"},
215 {HAL_PIXEL_FORMAT_RGBA_4444, "RGBA4444"},
Louis Huemillerb5265942010-12-12 23:05:31 -0800216 {HAL_PIXEL_FORMAT_YV12, "YV12"},
Louis Huemiller365b2c62010-11-22 18:05:30 -0800217};
218const unsigned int blendingOps[] = {
219 HWC_BLENDING_NONE,
220 HWC_BLENDING_PREMULT,
221 HWC_BLENDING_COVERAGE,
222};
223const unsigned int layerFlags[] = {
224 HWC_SKIP_LAYER,
225};
226const vector<unsigned int> vecLayerFlags(layerFlags,
227 layerFlags + NUMA(layerFlags));
228
229const unsigned int transformFlags[] = {
230 HWC_TRANSFORM_FLIP_H,
231 HWC_TRANSFORM_FLIP_V,
232 HWC_TRANSFORM_ROT_90,
233 // ROT_180 & ROT_270 intentionally not listed, because they
234 // they are formed from combinations of the flags already listed.
235};
236const vector<unsigned int> vecTransformFlags(transformFlags,
237 transformFlags + NUMA(transformFlags));
238
239// File scope globals
240static const int texUsage = GraphicBuffer::USAGE_HW_TEXTURE |
241 GraphicBuffer::USAGE_SW_WRITE_RARELY;
242static hw_module_t const *hwcModule;
243static hwc_composer_device_t *hwcDevice;
244static vector <vector <sp<GraphicBuffer> > > frames;
245static EGLDisplay dpy;
246static EGLContext context;
247static EGLSurface surface;
248static EGLint width, height;
249
250// File scope prototypes
251static void execCmd(const char *cmd);
252static void checkEglError(const char* op, EGLBoolean returnVal = EGL_TRUE);
253static void checkGlError(const char* op);
254static void printEGLConfiguration(EGLDisplay dpy, EGLConfig config);
255static void printGLString(const char *name, GLenum s);
256static hwc_layer_list_t *createLayerList(size_t numLayers);
257static void freeLayerList(hwc_layer_list_t *list);
258static void fillColor(GraphicBuffer *gBuf, RGBColor color, float trans);
259static void fillColor(GraphicBuffer *gBuf, YUVColor color, float trans);
260void init(void);
261void initFrames(unsigned int seed);
262void displayList(hwc_layer_list_t *list);
263void displayListPrepareModifiable(hwc_layer_list_t *list);
264void displayListHandles(hwc_layer_list_t *list);
265const char *graphicFormat2str(unsigned int format);
266template <class T> vector<T> vectorRandSelect(const vector<T>& vec, size_t num);
267template <class T> T vectorOr(const vector<T>& vec);
268
269/*
270 * Main
271 *
272 * Performs the following high-level sequence of operations:
273 *
274 * 1. Command-line parsing
275 *
276 * 2. Initialization
277 *
278 * 3. For each pass:
279 *
280 * a. If pass is first pass or in a different group from the
281 * previous pass, initialize the array of graphic buffers.
282 *
283 * b. Create a HWC list with room to specify a prandomly
284 * selected number of layers.
285 *
286 * c. Select a subset of the rows from the graphic buffer array,
287 * such that there is a unique row to be used for each
288 * of the layers in the HWC list.
289 *
290 * d. Prandomly fill in the HWC list with handles
291 * selected from any of the columns of the selected row.
292 *
293 * e. Pass the populated list to the HWC prepare call.
294 *
295 * f. Pass the populated list to the HWC set call.
296 *
297 * g. If additional set calls are to be made, then for each
298 * additional set call, select a new set of handles and
299 * perform the set call.
300 */
301int
302main(int argc, char *argv[])
303{
304 int rv, opt;
305 char *chptr;
306 unsigned int pass;
307 char cmd[MAXCMD];
308 struct timeval startTime, currentTime, delta;
309
310 testSetLogCatTag(LOG_TAG);
311
312 // Parse command line arguments
313 while ((opt = getopt(argc, argv, "vp:d:D:n:s:e:t:?h")) != -1) {
314 switch (opt) {
315 case 'd': // Delay after each set operation
316 perSetDelay = strtod(optarg, &chptr);
317 if ((*chptr != '\0') || (perSetDelay < 0.0)) {
318 testPrintE("Invalid command-line specified per pass delay of: "
319 "%s", optarg);
320 exit(1);
321 }
322 break;
323
324 case 'D': // End of test delay
325 // Delay between completion of final pass and restart
326 // of framework
327 endDelay = strtod(optarg, &chptr);
328 if ((*chptr != '\0') || (endDelay < 0.0)) {
329 testPrintE("Invalid command-line specified end of test delay "
330 "of: %s", optarg);
331 exit(2);
332 }
333 break;
334
335 case 't': // Duration
336 duration = strtod(optarg, &chptr);
337 if ((*chptr != '\0') || (duration < 0.0)) {
338 testPrintE("Invalid command-line specified duration of: %s",
339 optarg);
340 exit(3);
341 }
342 break;
343
344 case 'n': // Num set operations per pass
345 numSet = strtoul(optarg, &chptr, 10);
346 if (*chptr != '\0') {
347 testPrintE("Invalid command-line specified num set per pass "
348 "of: %s", optarg);
349 exit(4);
350 }
351 break;
352
353 case 's': // Starting Pass
354 sFlag = true;
355 if (pFlag) {
356 testPrintE("Invalid combination of command-line options.");
357 testPrintE(" The -p option is mutually exclusive from the");
358 testPrintE(" -s and -e options.");
359 exit(5);
360 }
361 startPass = strtoul(optarg, &chptr, 10);
362 if (*chptr != '\0') {
363 testPrintE("Invalid command-line specified starting pass "
364 "of: %s", optarg);
365 exit(6);
366 }
367 break;
368
369 case 'e': // Ending Pass
370 eFlag = true;
371 if (pFlag) {
372 testPrintE("Invalid combination of command-line options.");
373 testPrintE(" The -p option is mutually exclusive from the");
374 testPrintE(" -s and -e options.");
375 exit(7);
376 }
377 endPass = strtoul(optarg, &chptr, 10);
378 if (*chptr != '\0') {
379 testPrintE("Invalid command-line specified ending pass "
380 "of: %s", optarg);
381 exit(8);
382 }
383 break;
384
385 case 'p': // Run a single specified pass
386 pFlag = true;
387 if (sFlag || eFlag) {
388 testPrintE("Invalid combination of command-line options.");
389 testPrintE(" The -p option is mutually exclusive from the");
390 testPrintE(" -s and -e options.");
391 exit(9);
392 }
393 startPass = endPass = strtoul(optarg, &chptr, 10);
394 if (*chptr != '\0') {
395 testPrintE("Invalid command-line specified pass of: %s",
396 optarg);
397 exit(10);
398 }
399 break;
400
401 case 'v': // Verbose
402 verbose = true;
403 break;
404
405 case 'h': // Help
406 case '?':
407 default:
408 testPrintE(" %s [options]", basename(argv[0]));
409 testPrintE(" options:");
410 testPrintE(" -p Execute specified pass");
411 testPrintE(" -s Starting pass");
412 testPrintE(" -e Ending pass");
413 testPrintE(" -t Duration");
414 testPrintE(" -d Delay after each set operation");
415 testPrintE(" -D End of test delay");
416 testPrintE(" -n Num set operations per pass");
417 testPrintE(" -v Verbose");
418 exit(((optopt == 0) || (optopt == '?')) ? 0 : 11);
419 }
420 }
421 if (endPass < startPass) {
422 testPrintE("Unexpected ending pass before starting pass");
423 testPrintE(" startPass: %u endPass: %u", startPass, endPass);
424 exit(12);
425 }
426 if (argc != optind) {
427 testPrintE("Unexpected command-line postional argument");
428 testPrintE(" %s [-s start_pass] [-e end_pass] [-t duration]",
429 basename(argv[0]));
430 exit(13);
431 }
432 testPrintI("duration: %g", duration);
433 testPrintI("startPass: %u", startPass);
434 testPrintI("endPass: %u", endPass);
435 testPrintI("numSet: %u", numSet);
436
437 // Stop framework
438 rv = snprintf(cmd, sizeof(cmd), "%s", CMD_STOP_FRAMEWORK);
439 if (rv >= (signed) sizeof(cmd) - 1) {
440 testPrintE("Command too long for: %s", CMD_STOP_FRAMEWORK);
441 exit(14);
442 }
443 execCmd(cmd);
444 testDelay(1.0); // TODO - needs means to query whether asyncronous stop
445 // framework operation has completed. For now, just wait
446 // a long time.
447
448 init();
449
450 // For each pass
451 gettimeofday(&startTime, NULL);
452 for (pass = startPass; pass <= endPass; pass++) {
453 // Stop if duration of work has already been performed
454 gettimeofday(&currentTime, NULL);
455 delta = tvDelta(&startTime, &currentTime);
456 if (tv2double(&delta) > duration) { break; }
457
458 // Regenerate a new set of test frames when this pass is
459 // either the first pass or is in a different group then
460 // the previous pass. A group of passes are passes that
461 // all have the same quotient when their pass number is
462 // divided by passesPerGroup.
463 if ((pass == startPass)
464 || ((pass / passesPerGroup) != ((pass - 1) / passesPerGroup))) {
465 initFrames(pass / passesPerGroup);
466 }
467
468 testPrintI("==== Starting pass: %u", pass);
469
470 // Cause deterministic sequence of prandom numbers to be
471 // generated for this pass.
472 srand48(pass);
473
474 hwc_layer_list_t *list;
475 list = createLayerList(testRandMod(frames.size()) + 1);
476 if (list == NULL) {
477 testPrintE("createLayerList failed");
478 exit(20);
479 }
480
481 // Prandomly select a subset of frames to be used by this pass.
482 vector <vector <sp<GraphicBuffer> > > selectedFrames;
483 selectedFrames = vectorRandSelect(frames, list->numHwLayers);
484
485 // Any transform tends to create a layer that the hardware
486 // composer is unable to support and thus has to leave for
487 // SurfaceFlinger. Place heavy bias on specifying no transforms.
488 bool noTransform = testRandFract() > rareRatio;
489
490 for (unsigned int n1 = 0; n1 < list->numHwLayers; n1++) {
491 unsigned int idx = testRandMod(selectedFrames[n1].size());
492 sp<GraphicBuffer> gBuf = selectedFrames[n1][idx];
493 hwc_layer_t *layer = &list->hwLayers[n1];
494 layer->handle = gBuf->handle;
495
496 layer->blending = blendingOps[testRandMod(NUMA(blendingOps))];
497 layer->flags = (testRandFract() > rareRatio) ? 0
498 : vectorOr(vectorRandSelect(vecLayerFlags,
499 testRandMod(vecLayerFlags.size() + 1)));
500 layer->transform = (noTransform || testRandFract() > rareRatio) ? 0
501 : vectorOr(vectorRandSelect(vecTransformFlags,
502 testRandMod(vecTransformFlags.size() + 1)));
503 layer->sourceCrop.left = testRandMod(gBuf->getWidth());
504 layer->sourceCrop.top = testRandMod(gBuf->getHeight());
505 layer->sourceCrop.right = layer->sourceCrop.left
506 + testRandMod(gBuf->getWidth() - layer->sourceCrop.left) + 1;
507 layer->sourceCrop.bottom = layer->sourceCrop.top
508 + testRandMod(gBuf->getHeight() - layer->sourceCrop.top) + 1;
509 layer->displayFrame.left = testRandMod(width);
510 layer->displayFrame.top = testRandMod(height);
511 layer->displayFrame.right = layer->displayFrame.left
512 + testRandMod(width - layer->displayFrame.left) + 1;
513 layer->displayFrame.bottom = layer->displayFrame.top
514 + testRandMod(height - layer->displayFrame.top) + 1;
Louis Huemillerb5265942010-12-12 23:05:31 -0800515
516 // Increase the frequency that a scale factor of 1.0 from
517 // the sourceCrop to displayFrame occurs. This is the
518 // most common scale factor used by applications and would
519 // be rarely produced by this stress test without this
520 // logic.
521 if (testRandFract() <= freqRatio) {
522 // Only change to scale factor to 1.0 if both the
523 // width and height will fit.
524 int sourceWidth = layer->sourceCrop.right
525 - layer->sourceCrop.left;
526 int sourceHeight = layer->sourceCrop.bottom
527 - layer->sourceCrop.top;
528 if (((layer->displayFrame.left + sourceWidth) <= width)
529 && ((layer->displayFrame.top + sourceHeight) <= height)) {
530 layer->displayFrame.right = layer->displayFrame.left
531 + sourceWidth;
532 layer->displayFrame.bottom = layer->displayFrame.top
533 + sourceHeight;
534 }
535 }
536
Louis Huemiller365b2c62010-11-22 18:05:30 -0800537 layer->visibleRegionScreen.numRects = 1;
538 layer->visibleRegionScreen.rects = &layer->displayFrame;
539 }
540
541 // Perform prepare operation
542 if (verbose) { testPrintI("Prepare:"); displayList(list); }
543 hwcDevice->prepare(hwcDevice, list);
544 if (verbose) {
545 testPrintI("Post Prepare:");
546 displayListPrepareModifiable(list);
547 }
548
549 // Turn off the geometry changed flag
550 list->flags &= ~HWC_GEOMETRY_CHANGED;
551
552 // Perform the set operation(s)
553 if (verbose) {testPrintI("Set:"); }
554 for (unsigned int n1 = 0; n1 < numSet; n1++) {
555 if (verbose) {displayListHandles(list); }
556 hwcDevice->set(hwcDevice, dpy, surface, list);
557
558 // Prandomly select a new set of handles
559 for (unsigned int n1 = 0; n1 < list->numHwLayers; n1++) {
560 unsigned int idx = testRandMod(selectedFrames[n1].size());
561 sp<GraphicBuffer> gBuf = selectedFrames[n1][idx];
562 hwc_layer_t *layer = &list->hwLayers[n1];
563 layer->handle = (native_handle_t *) gBuf->handle;
564 }
565
566 testDelay(perSetDelay);
567 }
568
569
570 freeLayerList(list);
571 testPrintI("==== Completed pass: %u", pass);
572 }
573
574 testDelay(endDelay);
575
576 // Start framework
577 rv = snprintf(cmd, sizeof(cmd), "%s", CMD_START_FRAMEWORK);
578 if (rv >= (signed) sizeof(cmd) - 1) {
579 testPrintE("Command too long for: %s", CMD_START_FRAMEWORK);
580 exit(21);
581 }
582 execCmd(cmd);
583
584 testPrintI("Successfully completed %u passes", pass - startPass);
585
586 return 0;
587}
588
589/*
590 * Execute Command
591 *
592 * Executes the command pointed to by cmd. Output from the
593 * executed command is captured and sent to LogCat Info. Once
594 * the command has finished execution, it's exit status is captured
595 * and checked for an exit status of zero. Any other exit status
596 * causes diagnostic information to be printed and an immediate
597 * testcase failure.
598 */
599static void execCmd(const char *cmd)
600{
601 FILE *fp;
602 int rv;
603 int status;
604 char str[MAXSTR];
605
606 // Display command to be executed
607 testPrintI("cmd: %s", cmd);
608
609 // Execute the command
610 fflush(stdout);
611 if ((fp = popen(cmd, "r")) == NULL) {
612 testPrintE("execCmd popen failed, errno: %i", errno);
613 exit(30);
614 }
615
616 // Obtain and display each line of output from the executed command
617 while (fgets(str, sizeof(str), fp) != NULL) {
618 if ((strlen(str) > 1) && (str[strlen(str) - 1] == '\n')) {
619 str[strlen(str) - 1] = '\0';
620 }
621 testPrintI(" out: %s", str);
622 }
623
624 // Obtain and check return status of executed command.
625 // Fail on non-zero exit status
626 status = pclose(fp);
627 if (!(WIFEXITED(status) && (WEXITSTATUS(status) == 0))) {
628 testPrintE("Unexpected command failure");
629 testPrintE(" status: %#x", status);
630 if (WIFEXITED(status)) {
631 testPrintE("WEXITSTATUS: %i", WEXITSTATUS(status));
632 }
633 if (WIFSIGNALED(status)) {
634 testPrintE("WTERMSIG: %i", WTERMSIG(status));
635 }
636 exit(31);
637 }
638}
639
640static void checkEglError(const char* op, EGLBoolean returnVal) {
641 if (returnVal != EGL_TRUE) {
642 testPrintE("%s() returned %d", op, returnVal);
643 }
644
645 for (EGLint error = eglGetError(); error != EGL_SUCCESS; error
646 = eglGetError()) {
647 testPrintE("after %s() eglError %s (0x%x)",
648 op, EGLUtils::strerror(error), error);
649 }
650}
651
652static void checkGlError(const char* op) {
653 for (GLint error = glGetError(); error; error
654 = glGetError()) {
655 testPrintE("after %s() glError (0x%x)", op, error);
656 }
657}
658
659static void printEGLConfiguration(EGLDisplay dpy, EGLConfig config) {
660
661#define X(VAL) {VAL, #VAL}
662 struct {EGLint attribute; const char* name;} names[] = {
663 X(EGL_BUFFER_SIZE),
664 X(EGL_ALPHA_SIZE),
665 X(EGL_BLUE_SIZE),
666 X(EGL_GREEN_SIZE),
667 X(EGL_RED_SIZE),
668 X(EGL_DEPTH_SIZE),
669 X(EGL_STENCIL_SIZE),
670 X(EGL_CONFIG_CAVEAT),
671 X(EGL_CONFIG_ID),
672 X(EGL_LEVEL),
673 X(EGL_MAX_PBUFFER_HEIGHT),
674 X(EGL_MAX_PBUFFER_PIXELS),
675 X(EGL_MAX_PBUFFER_WIDTH),
676 X(EGL_NATIVE_RENDERABLE),
677 X(EGL_NATIVE_VISUAL_ID),
678 X(EGL_NATIVE_VISUAL_TYPE),
679 X(EGL_SAMPLES),
680 X(EGL_SAMPLE_BUFFERS),
681 X(EGL_SURFACE_TYPE),
682 X(EGL_TRANSPARENT_TYPE),
683 X(EGL_TRANSPARENT_RED_VALUE),
684 X(EGL_TRANSPARENT_GREEN_VALUE),
685 X(EGL_TRANSPARENT_BLUE_VALUE),
686 X(EGL_BIND_TO_TEXTURE_RGB),
687 X(EGL_BIND_TO_TEXTURE_RGBA),
688 X(EGL_MIN_SWAP_INTERVAL),
689 X(EGL_MAX_SWAP_INTERVAL),
690 X(EGL_LUMINANCE_SIZE),
691 X(EGL_ALPHA_MASK_SIZE),
692 X(EGL_COLOR_BUFFER_TYPE),
693 X(EGL_RENDERABLE_TYPE),
694 X(EGL_CONFORMANT),
695 };
696#undef X
697
698 for (size_t j = 0; j < sizeof(names) / sizeof(names[0]); j++) {
699 EGLint value = -1;
700 EGLint returnVal = eglGetConfigAttrib(dpy, config, names[j].attribute, &value);
701 EGLint error = eglGetError();
702 if (returnVal && error == EGL_SUCCESS) {
703 testPrintI(" %s: %d (%#x)", names[j].name, value, value);
704 }
705 }
706 testPrintI("");
707}
708
709static void printGLString(const char *name, GLenum s)
710{
711 const char *v = (const char *) glGetString(s);
712
713 if (v == NULL) {
714 testPrintI("GL %s unknown", name);
715 } else {
716 testPrintI("GL %s = %s", name, v);
717 }
718}
719
720/*
721 * createLayerList
722 * dynamically creates layer list with numLayers worth
723 * of hwLayers entries.
724 */
725static hwc_layer_list_t *createLayerList(size_t numLayers)
726{
727 hwc_layer_list_t *list;
728
729 size_t size = sizeof(hwc_layer_list) + numLayers * sizeof(hwc_layer_t);
730 if ((list = (hwc_layer_list_t *) calloc(1, size)) == NULL) {
731 return NULL;
732 }
733 list->flags = HWC_GEOMETRY_CHANGED;
734 list->numHwLayers = numLayers;
735
736 return list;
737}
738
739/*
740 * freeLayerList
741 * Frees memory previous allocated via createLayerList().
742 */
743static void freeLayerList(hwc_layer_list_t *list)
744{
745 free(list);
746}
747
748static void fillColor(GraphicBuffer *gBuf, RGBColor color, float trans)
749{
750 unsigned char* buf = NULL;
751 status_t err;
752 unsigned int numPixels = gBuf->getWidth() * gBuf->getHeight();
753 uint32_t pixel;
754
755 // RGB 2 YUV conversion ratios
756 const struct rgb2yuvRatios {
757 int format;
758 float weightRed;
759 float weightBlu;
760 float weightGrn;
761 } rgb2yuvRatios[] = {
762 { HAL_PIXEL_FORMAT_YV12, 0.299, 0.114, 0.587 },
763 };
764
765 const struct rgbAttrib {
766 int format;
767 bool hostByteOrder;
768 size_t bytes;
769 size_t rOffset;
770 size_t rSize;
771 size_t gOffset;
772 size_t gSize;
773 size_t bOffset;
774 size_t bSize;
775 size_t aOffset;
776 size_t aSize;
777 } rgbAttributes[] = {
778 {HAL_PIXEL_FORMAT_RGBA_8888, false, 4, 0, 8, 8, 8, 16, 8, 24, 8},
779 {HAL_PIXEL_FORMAT_RGBX_8888, false, 4, 0, 8, 8, 8, 16, 8, 0, 0},
780 {HAL_PIXEL_FORMAT_RGB_888, false, 3, 0, 8, 8, 8, 16, 8, 0, 0},
781 {HAL_PIXEL_FORMAT_RGB_565, true, 2, 0, 5, 5, 6, 11, 5, 0, 0},
782 {HAL_PIXEL_FORMAT_BGRA_8888, false, 4, 16, 8, 8, 8, 0, 8, 24, 8},
783 {HAL_PIXEL_FORMAT_RGBA_5551, true , 2, 0, 5, 5, 5, 10, 5, 15, 1},
784 {HAL_PIXEL_FORMAT_RGBA_4444, false, 2, 12, 4, 0, 4, 4, 4, 8, 4},
785 };
786
787 // If YUV format, convert color and pass work to YUV color fill
788 for (unsigned int n1 = 0; n1 < NUMA(rgb2yuvRatios); n1++) {
789 if (gBuf->getPixelFormat() == rgb2yuvRatios[n1].format) {
790 float wr = rgb2yuvRatios[n1].weightRed;
791 float wb = rgb2yuvRatios[n1].weightBlu;
792 float wg = rgb2yuvRatios[n1].weightGrn;
793 float y = wr * color.r() + wb * color.b() + wg * color.g();
794 float u = 0.5 * ((color.b() - y) / (1 - wb)) + 0.5;
795 float v = 0.5 * ((color.r() - y) / (1 - wr)) + 0.5;
796 YUVColor yuvColor(y, u, v);
797 fillColor(gBuf, yuvColor, trans);
798 return;
799 }
800 }
801
802 const struct rgbAttrib *attrib;
803 for (attrib = rgbAttributes; attrib < rgbAttributes + NUMA(rgbAttributes);
804 attrib++) {
805 if (attrib->format == gBuf->getPixelFormat()) { break; }
806 }
807 if (attrib >= rgbAttributes + NUMA(rgbAttributes)) {
808 testPrintE("fillColor rgb unsupported format of: %u",
809 gBuf->getPixelFormat());
810 exit(50);
811 }
812
813 pixel = htonl((uint32_t) (((1 << attrib->rSize) - 1) * color.r())
814 << ((sizeof(pixel) * BITSPERBYTE)
815 - (attrib->rOffset + attrib->rSize)));
816 pixel |= htonl((uint32_t) (((1 << attrib->gSize) - 1) * color.g())
817 << ((sizeof(pixel) * BITSPERBYTE)
818 - (attrib->gOffset + attrib->gSize)));
819 pixel |= htonl((uint32_t) (((1 << attrib->bSize) - 1) * color.b())
820 << ((sizeof(pixel) * BITSPERBYTE)
821 - (attrib->bOffset + attrib->bSize)));
822 if (attrib->aSize) {
823 pixel |= htonl((uint32_t) (((1 << attrib->aSize) - 1) * trans)
824 << ((sizeof(pixel) * BITSPERBYTE)
825 - (attrib->aOffset + attrib->aSize)));
826 }
827 if (attrib->hostByteOrder) {
828 pixel = ntohl(pixel);
829 pixel >>= sizeof(pixel) * BITSPERBYTE - attrib->bytes * BITSPERBYTE;
830 }
831
832 err = gBuf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&buf));
833 if (err != 0) {
834 testPrintE("fillColor rgb lock failed: %d", err);
835 exit(51);
836 }
837
838 for (unsigned int n1 = 0; n1 < numPixels; n1++) {
839 memmove(buf, &pixel, attrib->bytes);
840 buf += attrib->bytes;
841 }
842
843 err = gBuf->unlock();
844 if (err != 0) {
845 testPrintE("fillColor rgb unlock failed: %d", err);
846 exit(52);
847 }
848}
849
850static void fillColor(GraphicBuffer *gBuf, YUVColor color, float trans)
851{
852 unsigned char* buf = NULL;
853 status_t err;
854 unsigned int width = gBuf->getWidth();
855 unsigned int height = gBuf->getHeight();
856
857 const struct yuvAttrib {
858 int format;
859 size_t padWidth;
860 bool planar;
861 unsigned int uSubSampX;
862 unsigned int uSubSampY;
863 unsigned int vSubSampX;
864 unsigned int vSubSampY;
865 } yuvAttributes[] = {
866 { HAL_PIXEL_FORMAT_YV12, 16, true, 2, 2, 2, 2},
867 };
868
869 const struct yuvAttrib *attrib;
870 for (attrib = yuvAttributes; attrib < yuvAttributes + NUMA(yuvAttributes);
871 attrib++) {
872 if (attrib->format == gBuf->getPixelFormat()) { break; }
873 }
874 if (attrib >= yuvAttributes + NUMA(yuvAttributes)) {
875 testPrintE("fillColor yuv unsupported format of: %u",
876 gBuf->getPixelFormat());
877 exit(60);
878 }
879
880 assert(attrib->planar == true); // So far, only know how to handle planar
881
882 // If needed round width up to pad size
883 if (width % attrib->padWidth) {
884 width += attrib->padWidth - (width % attrib->padWidth);
885 }
886 assert((width % attrib->padWidth) == 0);
887
888 err = gBuf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&buf));
889 if (err != 0) {
890 testPrintE("fillColor lock failed: %d", err);
891 exit(61);
892 }
893
894 // Fill in Y component
895 for (unsigned int x = 0; x < width; x++) {
896 for (unsigned int y = 0; y < height; y++) {
897 *buf++ = (x < gBuf->getWidth()) ? (255 * color.y()) : 0;
898 }
899 }
900
901 // Fill in U component
902 for (unsigned int x = 0; x < width; x += attrib->uSubSampX) {
903 for (unsigned int y = 0; y < height; y += attrib->uSubSampY) {
904 *buf++ = (x < gBuf->getWidth()) ? (255 * color.u()) : 0;
905 }
906 }
907
908 // Fill in V component
909 for (unsigned int x = 0; x < width; x += attrib->vSubSampX) {
910 for (unsigned int y = 0; y < height; y += attrib->vSubSampY) {
911 *buf++ = (x < gBuf->getWidth()) ? (255 * color.v()) : 0;
912 }
913 }
914
915 err = gBuf->unlock();
916 if (err != 0) {
917 testPrintE("fillColor unlock failed: %d", err);
918 exit(62);
919 }
920}
921
922void init(void)
923{
924 int rv;
925
926 EGLBoolean returnValue;
927 EGLConfig myConfig = {0};
928 EGLint contextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
929 EGLint sConfigAttribs[] = {
930 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
931 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
932 EGL_NONE };
933 EGLint majorVersion, minorVersion;
934
935 checkEglError("<init>");
936 dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
937 checkEglError("eglGetDisplay");
938 if (dpy == EGL_NO_DISPLAY) {
939 testPrintE("eglGetDisplay returned EGL_NO_DISPLAY");
940 exit(70);
941 }
942
943 returnValue = eglInitialize(dpy, &majorVersion, &minorVersion);
944 checkEglError("eglInitialize", returnValue);
945 testPrintI("EGL version %d.%d", majorVersion, minorVersion);
946 if (returnValue != EGL_TRUE) {
947 testPrintE("eglInitialize failed");
948 exit(71);
949 }
950
951 EGLNativeWindowType window = android_createDisplaySurface();
952 if (window == NULL) {
953 testPrintE("android_createDisplaySurface failed");
954 exit(72);
955 }
956 returnValue = EGLUtils::selectConfigForNativeWindow(dpy,
957 sConfigAttribs, window, &myConfig);
958 if (returnValue) {
959 testPrintE("EGLUtils::selectConfigForNativeWindow() returned %d",
960 returnValue);
961 exit(73);
962 }
963 checkEglError("EGLUtils::selectConfigForNativeWindow");
964
965 testPrintI("Chose this configuration:");
966 printEGLConfiguration(dpy, myConfig);
967
968 surface = eglCreateWindowSurface(dpy, myConfig, window, NULL);
969 checkEglError("eglCreateWindowSurface");
970 if (surface == EGL_NO_SURFACE) {
971 testPrintE("gelCreateWindowSurface failed.");
972 exit(74);
973 }
974
975 context = eglCreateContext(dpy, myConfig, EGL_NO_CONTEXT, contextAttribs);
976 checkEglError("eglCreateContext");
977 if (context == EGL_NO_CONTEXT) {
978 testPrintE("eglCreateContext failed");
979 exit(75);
980 }
981 returnValue = eglMakeCurrent(dpy, surface, surface, context);
982 checkEglError("eglMakeCurrent", returnValue);
983 if (returnValue != EGL_TRUE) {
984 testPrintE("eglMakeCurrent failed");
985 exit(76);
986 }
987 eglQuerySurface(dpy, surface, EGL_WIDTH, &width);
988 checkEglError("eglQuerySurface");
989 eglQuerySurface(dpy, surface, EGL_HEIGHT, &height);
990 checkEglError("eglQuerySurface");
991
992 fprintf(stderr, "Window dimensions: %d x %d", width, height);
993
994 printGLString("Version", GL_VERSION);
995 printGLString("Vendor", GL_VENDOR);
996 printGLString("Renderer", GL_RENDERER);
997 printGLString("Extensions", GL_EXTENSIONS);
998
999 if ((rv = hw_get_module(HWC_HARDWARE_MODULE_ID, &hwcModule)) != 0) {
1000 testPrintE("hw_get_module failed, rv: %i", rv);
1001 errno = -rv;
1002 perror(NULL);
1003 exit(77);
1004 }
1005 if ((rv = hwc_open(hwcModule, &hwcDevice)) != 0) {
1006 testPrintE("hwc_open failed, rv: %i", rv);
1007 errno = -rv;
1008 perror(NULL);
1009 exit(78);
1010 }
1011
1012 testPrintI("");
1013}
1014
1015/*
1016 * Initialize Frames
1017 *
1018 * Creates an array of graphic buffers, within the global variable
1019 * named frames. The graphic buffers are contained within a vector of
1020 * verctors. All the graphic buffers in a particular row are of the same
1021 * format and dimension. Each graphic buffer is uniformly filled with a
1022 * prandomly selected color. It is likely that each buffer, even
1023 * in the same row, will be filled with a unique color.
1024 */
1025void initFrames(unsigned int seed)
1026{
Louis Huemillerb5265942010-12-12 23:05:31 -08001027 int rv;
Louis Huemiller365b2c62010-11-22 18:05:30 -08001028 const size_t maxRows = 5;
1029 const size_t minCols = 2; // Need at least double buffering
1030 const size_t maxCols = 4; // One more than triple buffering
1031
1032 if (verbose) { testPrintI("initFrames seed: %u", seed); }
1033 srand48(seed);
1034 size_t rows = testRandMod(maxRows) + 1;
1035
1036 frames.clear();
1037 frames.resize(rows);
1038
1039 for (unsigned int row = 0; row < rows; row++) {
1040 // All frames within a row have to have the same format and
1041 // dimensions. Width and height need to be >= 1.
1042 int format = graphicFormat[testRandMod(NUMA(graphicFormat))].format;
1043 size_t w = (width * maxSizeRatio) * testRandFract();
1044 size_t h = (height * maxSizeRatio) * testRandFract();
1045 w = max(1u, w);
1046 h = max(1u, h);
1047 if (verbose) {
1048 testPrintI(" frame %u width: %u height: %u format: %u %s",
1049 row, w, h, format, graphicFormat2str(format));
1050 }
1051
1052 size_t cols = testRandMod((maxCols + 1) - minCols) + minCols;
1053 frames[row].resize(cols);
1054 for (unsigned int col = 0; col < cols; col++) {
1055 RGBColor color(testRandFract(), testRandFract(), testRandFract());
1056 float transp = testRandFract();
1057
1058 frames[row][col] = new GraphicBuffer(w, h, format, texUsage);
Louis Huemillerb5265942010-12-12 23:05:31 -08001059 if ((rv = frames[row][col]->initCheck()) != NO_ERROR) {
1060 testPrintE("GraphicBuffer initCheck failed, rv: %i", rv);
1061 testPrintE(" frame %u width: %u height: %u format: %u %s",
1062 row, w, h, format, graphicFormat2str(format));
1063 exit(80);
1064 }
1065
Louis Huemiller365b2c62010-11-22 18:05:30 -08001066 fillColor(frames[row][col].get(), color, transp);
1067 if (verbose) {
1068 testPrintI(" buf: %p handle: %p color: <%f, %f, %f> "
1069 "transp: %f",
1070 frames[row][col].get(), frames[row][col]->handle,
1071 color.r(), color.g(), color.b(), transp);
1072 }
1073 }
1074 }
1075}
1076
1077void displayList(hwc_layer_list_t *list)
1078{
1079 testPrintI(" flags: %#x%s", list->flags,
1080 (list->flags & HWC_GEOMETRY_CHANGED) ? " GEOMETRY_CHANGED" : "");
1081 testPrintI(" numHwLayers: %u", list->numHwLayers);
1082
1083 for (unsigned int layer = 0; layer < list->numHwLayers; layer++) {
1084 testPrintI(" layer %u compositionType: %#x%s%s", layer,
1085 list->hwLayers[layer].compositionType,
1086 (list->hwLayers[layer].compositionType == HWC_FRAMEBUFFER)
1087 ? " FRAMEBUFFER" : "",
1088 (list->hwLayers[layer].compositionType == HWC_OVERLAY)
1089 ? " OVERLAY" : "");
1090
1091 testPrintI(" hints: %#x",
1092 list->hwLayers[layer].hints,
1093 (list->hwLayers[layer].hints & HWC_HINT_TRIPLE_BUFFER)
1094 ? " TRIPLE_BUFFER" : "",
1095 (list->hwLayers[layer].hints & HWC_HINT_CLEAR_FB)
1096 ? " CLEAR_FB" : "");
1097
1098 testPrintI(" flags: %#x%s",
1099 list->hwLayers[layer].flags,
1100 (list->hwLayers[layer].flags & HWC_SKIP_LAYER)
1101 ? " SKIP_LAYER" : "");
1102
1103 testPrintI(" handle: %p",
1104 list->hwLayers[layer].handle);
1105
1106 // Intentionally skipped display of ROT_180 & ROT_270,
1107 // which are formed from combinations of the other flags.
1108 testPrintI(" transform: %#x%s%s%s",
1109 list->hwLayers[layer].transform,
1110 (list->hwLayers[layer].transform & HWC_TRANSFORM_FLIP_H)
1111 ? " FLIP_H" : "",
1112 (list->hwLayers[layer].transform & HWC_TRANSFORM_FLIP_V)
1113 ? " FLIP_V" : "",
1114 (list->hwLayers[layer].transform & HWC_TRANSFORM_ROT_90)
1115 ? " ROT_90" : "");
1116
1117 testPrintI(" blending: %#x",
1118 list->hwLayers[layer].blending,
1119 (list->hwLayers[layer].blending == HWC_BLENDING_NONE)
1120 ? " NONE" : "",
1121 (list->hwLayers[layer].blending == HWC_BLENDING_PREMULT)
1122 ? " PREMULT" : "",
1123 (list->hwLayers[layer].blending == HWC_BLENDING_COVERAGE)
1124 ? " COVERAGE" : "");
1125
1126 testPrintI(" sourceCrop: [%i, %i, %i, %i]",
1127 list->hwLayers[layer].sourceCrop.left,
1128 list->hwLayers[layer].sourceCrop.top,
1129 list->hwLayers[layer].sourceCrop.right,
1130 list->hwLayers[layer].sourceCrop.bottom);
1131
1132 testPrintI(" displayFrame: [%i, %i, %i, %i]",
1133 list->hwLayers[layer].displayFrame.left,
1134 list->hwLayers[layer].displayFrame.top,
1135 list->hwLayers[layer].displayFrame.right,
1136 list->hwLayers[layer].displayFrame.bottom);
Louis Huemillerb5265942010-12-12 23:05:31 -08001137 testPrintI(" scaleFactor: [%f %f]",
1138 (float) (list->hwLayers[layer].displayFrame.right
1139 - list->hwLayers[layer].displayFrame.left)
1140 / (float) (list->hwLayers[layer].sourceCrop.right
1141 - list->hwLayers[layer].sourceCrop.left),
1142 (float) (list->hwLayers[layer].displayFrame.bottom
1143 - list->hwLayers[layer].displayFrame.top)
1144 / (float) (list->hwLayers[layer].sourceCrop.bottom
1145 - list->hwLayers[layer].sourceCrop.top));
Louis Huemiller365b2c62010-11-22 18:05:30 -08001146 }
1147}
1148
1149/*
1150 * Display List Prepare Modifiable
1151 *
1152 * Displays the portions of a list that are meant to be modified by
1153 * a prepare call.
1154 */
1155void displayListPrepareModifiable(hwc_layer_list_t *list)
1156{
1157 for (unsigned int layer = 0; layer < list->numHwLayers; layer++) {
1158 testPrintI(" layer %u compositionType: %#x%s%s", layer,
1159 list->hwLayers[layer].compositionType,
1160 (list->hwLayers[layer].compositionType == HWC_FRAMEBUFFER)
1161 ? " FRAMEBUFFER" : "",
1162 (list->hwLayers[layer].compositionType == HWC_OVERLAY)
1163 ? " OVERLAY" : "");
1164 testPrintI(" hints: %#x%s%s",
1165 list->hwLayers[layer].hints,
1166 (list->hwLayers[layer].hints & HWC_HINT_TRIPLE_BUFFER)
1167 ? " TRIPLE_BUFFER" : "",
1168 (list->hwLayers[layer].hints & HWC_HINT_CLEAR_FB)
1169 ? " CLEAR_FB" : "");
1170 }
1171}
1172
1173/*
1174 * Display List Handles
1175 *
1176 * Displays the handles of all the graphic buffers in the list.
1177 */
1178void displayListHandles(hwc_layer_list_t *list)
1179{
1180 const unsigned int maxLayersPerLine = 6;
1181
1182 ostringstream str(" layers:");
1183 for (unsigned int layer = 0; layer < list->numHwLayers; layer++) {
1184 str << ' ' << list->hwLayers[layer].handle;
1185 if (((layer % maxLayersPerLine) == (maxLayersPerLine - 1))
1186 && (layer != list->numHwLayers - 1)) {
1187 testPrintI("%s", str.str().c_str());
1188 str.str(" ");
1189 }
1190 }
1191 testPrintI("%s", str.str().c_str());
1192}
1193
1194const char *graphicFormat2str(unsigned int format)
1195{
1196 const static char *unknown = "unknown";
1197
1198 for (unsigned int n1 = 0; n1 < NUMA(graphicFormat); n1++) {
1199 if (format == graphicFormat[n1].format) {
1200 return graphicFormat[n1].desc;
1201 }
1202 }
1203
1204 return unknown;
1205}
1206
1207/*
1208 * Vector Random Select
1209 *
1210 * Prandomly selects and returns num elements from vec.
1211 */
1212template <class T>
1213vector<T> vectorRandSelect(const vector<T>& vec, size_t num)
1214{
1215 vector<T> rv = vec;
1216
1217 while (rv.size() > num) {
1218 rv.erase(rv.begin() + testRandMod(rv.size()));
1219 }
1220
1221 return rv;
1222}
1223
1224/*
1225 * Vector Or
1226 *
1227 * Or's togethen the values of each element of vec and returns the result.
1228 */
1229template <class T>
1230T vectorOr(const vector<T>& vec)
1231{
1232 T rv = 0;
1233
1234 for (size_t n1 = 0; n1 < vec.size(); n1++) {
1235 rv |= vec[n1];
1236 }
1237
1238 return rv;
1239}