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