blob: ed74cbe7284c35eb1e3905645184a5fd787e1884 [file] [log] [blame]
Louis Huemiller585cd4f2011-01-09 10:59:31 -08001/*
2 * Copyright (C) 2011 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 Commit Points
20 *
21 * Synopsis
22 * hwcCommit [options] graphicFormat ...
23 * options:
24 * -s [width, height] - Starting dimension
25 * -v - Verbose
26 *
27 * graphic formats:
28 * RGBA8888 (reference frame default)
29 * RGBX8888
30 * RGB888
31 * RGB565
32 * BGRA8888
33 * RGBA5551
34 * RGBA4444
35 * YV12
36 *
37 * Description
38 * The Hardware Composer (HWC) Commit test is a benchmark that
39 * discovers the points at which the HWC will commit to rendering an
40 * overlay(s). Before rendering a set of overlays, the HWC is shown
41 * the list through a prepare call. During the prepare call the HWC
42 * is able to examine the list and specify which overlays it is able
43 * to handle. The overlays that it can't handle are typically composited
44 * by a higher level (e.g. Surface Flinger) and then the original list
45 * plus a composit of what HWC passed on are provided back to the HWC
46 * for rendering.
47 *
48 * Once an implementation of the HWC has been shipped, a regression would
49 * likely occur if a latter implementation started passing on conditions
50 * that it used to commit to. The primary purpose of this benchmark
51 * is the automated discovery of the commit points, where an implementation
52 * is on the edge between committing and not committing. These are commonly
53 * referred to as commit points. Between implementations changes to the
54 * commit points are allowed, as long as they improve what the HWC commits
55 * to. Once an implementation of the HWC is shipped, the commit points are
56 * not allowed to regress in future implementations.
57 *
58 * This benchmark takes a sampling and then adjusts until it finds a
59 * commit point. It doesn't exhaustively check all possible conditions,
60 * which do to the number of combinations would be impossible. Instead
61 * it starts its search from a starting dimension, that can be changed
62 * via the -s option. The search is also bounded by a set of search
63 * limits, that are hard-coded into a structure of constants named
64 * searchLimits. Results that happen to reach a searchLimit are prefixed
65 * with >=, so that it is known that the value could possibly be larger.
66 *
67 * Measurements are made for each of the graphic formats specified as
68 * positional parameters on the command-line. If no graphic formats
69 * are specified on the command line, then by default measurements are
70 * made and reported for each of the known graphic format.
71 */
72
73#include <algorithm>
74#include <assert.h>
75#include <cerrno>
76#include <cmath>
77#include <cstdlib>
78#include <ctime>
79#include <istream>
80#include <libgen.h>
81#include <list>
82#include <sched.h>
83#include <sstream>
84#include <stdint.h>
85#include <string.h>
86#include <unistd.h>
87#include <vector>
88
89#include <sys/syscall.h>
90#include <sys/types.h>
91#include <sys/wait.h>
92
93#include <EGL/egl.h>
94#include <EGL/eglext.h>
95#include <GLES2/gl2.h>
96#include <GLES2/gl2ext.h>
97
98#include <ui/FramebufferNativeWindow.h>
99#include <ui/GraphicBuffer.h>
100#include <ui/EGLUtils.h>
101
102#define LOG_TAG "hwcCommitTest"
103#include <utils/Log.h>
104#include <testUtil.h>
105
106#include <hardware/hwcomposer.h>
107
108#include <glTestLib.h>
109#include <hwc/hwcTestLib.h>
110
111using namespace std;
112using namespace android;
113
114// Defaults
115const HwcTestDim defaultStartDim = HwcTestDim(100, 100);
116const bool defaultVerbose = false;
117
118const uint32_t defaultFormat = HAL_PIXEL_FORMAT_RGBA_8888;
119const int32_t defaultTransform = 0;
120const uint32_t defaultBlend = HWC_BLENDING_NONE;
121const ColorFract defaultColor(0.5, 0.5, 0.5);
122const float defaultAlpha = 1.0; // Opaque
123const HwcTestDim defaultSourceDim(1, 1);
124const struct hwc_rect defaultSourceCrop = {0, 0, 1, 1};
125const struct hwc_rect defaultDisplayFrame = {0, 0, 100, 100};
126
127// Global Constants
128const struct searchLimits {
129 uint32_t numOverlays;
130 HwcTestDim sourceCrop;
131} searchLimits = {
132 10,
133 HwcTestDim(3000, 2000),
134};
135const struct transformType {
136 const char *desc;
137 uint32_t id;
138} transformType[] = {
139 {"fliph", HWC_TRANSFORM_FLIP_H},
140 {"flipv", HWC_TRANSFORM_FLIP_V},
141 {"rot90", HWC_TRANSFORM_ROT_90},
142 {"rot180", HWC_TRANSFORM_ROT_180},
143 {"rot270", HWC_TRANSFORM_ROT_270},
144};
145const struct blendType {
146 const char *desc;
147 uint32_t id;
148} blendType[] = {
149 {"none", HWC_BLENDING_NONE},
150 {"premult", HWC_BLENDING_PREMULT},
151 {"coverage", HWC_BLENDING_COVERAGE},
152};
153
154// Defines
155#define MAXCMD 200
156#define CMD_STOP_FRAMEWORK "stop 2>&1"
157#define CMD_START_FRAMEWORK "start 2>&1"
158
159// Macros
160#define NUMA(a) (sizeof(a) / sizeof(a [0])) // Num elements in an array
161
162// Local types
163class Rectangle {
164public:
165 Rectangle(uint32_t graphicFormat = defaultFormat,
166 HwcTestDim dfDim = HwcTestDim(1, 1),
167 HwcTestDim sDim = HwcTestDim(1, 1));
168 void setSourceDim(HwcTestDim dim);
169
170 uint32_t format;
171 uint32_t transform;
172 int32_t blend;
173 ColorFract color;
174 float alpha;
175 HwcTestDim sourceDim;
176 struct hwc_rect sourceCrop;
177 struct hwc_rect displayFrame;
178};
179
180class Range {
181public:
182 Range(void) : _l(0), _u(0) {}
183 Range(uint32_t lower, uint32_t upper) : _l(lower), _u(upper) {}
184 uint32_t lower(void) { return _l; }
185 uint32_t upper(void) { return _u; }
186
187 operator string();
188
189private:
190 uint32_t _l; // lower
191 uint32_t _u; // upper
192};
193
194Range::operator string()
195{
196 ostringstream out;
197
198 out << '[' << _l << ", " << _u << ']';
199
200 return out.str();
201}
202
203class Rational {
204public:
205 Rational(void) : _n(0), _d(1) {}
206 Rational(uint32_t n, uint32_t d) : _n(n), _d(d) {}
207 uint32_t numerator(void) { return _n; }
208 uint32_t denominator(void) { return _d; }
209 void setNumerator(uint32_t numerator) { _n = numerator; }
210
211 bool operator==(const Rational& other) const;
212 bool operator!=(const Rational& other) const { return !(*this == other); }
213 bool operator<(const Rational& other) const;
214 bool operator>(const Rational& other) const {
215 return (!(*this == other) && !(*this < other));
216 }
217 static void double2Rational(double f, Range nRange, Range dRange,
218 Rational& lower, Rational& upper);
219
220 operator string() const;
221 operator double() const { return (double) _n / (double) _d; }
222
223
224private:
225 uint32_t _n;
226 uint32_t _d;
227};
228
229// Globals
230static const int texUsage = GraphicBuffer::USAGE_HW_TEXTURE |
231 GraphicBuffer::USAGE_SW_WRITE_RARELY;
232static hwc_composer_device_t *hwcDevice;
233static EGLDisplay dpy;
234static EGLSurface surface;
235static EGLint width, height;
236
237// Measurements
238struct meas {
239 uint32_t format;
240 uint32_t startDimOverlays;
241 uint32_t maxNonOverlapping;
242 uint32_t maxOverlapping;
243 list<uint32_t> transforms;
244 list<uint32_t> blends;
245 struct displayFrame {
246 uint32_t minWidth;
247 uint32_t minHeight;
248 HwcTestDim minDim;
249 uint32_t maxWidth;
250 uint32_t maxHeight;
251 HwcTestDim maxDim;
252 } df;
253 struct sourceCrop {
254 uint32_t minWidth;
255 uint32_t minHeight;
256 HwcTestDim minDim;
257 uint32_t maxWidth;
258 uint32_t maxHeight;
259 HwcTestDim maxDim;
260 Rational hScale;
261 HwcTestDim hScaleBestDf;
262 HwcTestDim hScaleBestSc;
263 Rational vScale;
264 HwcTestDim vScaleBestDf;
265 HwcTestDim vScaleBestSc;
266 } sc;
267};
268vector<meas> measurements;
269
270// Function prototypes
271uint32_t numOverlays(list<Rectangle>& rectList);
272uint32_t maxOverlays(uint32_t format, bool allowOverlap);
273list<uint32_t> supportedTransforms(uint32_t format);
274list<uint32_t> supportedBlends(uint32_t format);
275uint32_t dfMinWidth(uint32_t format);
276uint32_t dfMinHeight(uint32_t format);
277uint32_t dfMaxWidth(uint32_t format);
278uint32_t dfMaxHeight(uint32_t format);
279HwcTestDim dfMinDim(uint32_t format);
280HwcTestDim dfMaxDim(uint32_t format);
281uint32_t scMinWidth(uint32_t format, const HwcTestDim& dfDim);
282uint32_t scMinHeight(uint32_t format, const HwcTestDim& dfDim);
283uint32_t scMaxWidth(uint32_t format, const HwcTestDim& dfDim);
284uint32_t scMaxHeight(uint32_t format, const HwcTestDim& dfDim);
285HwcTestDim scMinDim(uint32_t format, const HwcTestDim& dfDim);
286HwcTestDim scMaxDim(uint32_t format, const HwcTestDim& dfDim);
287Rational scHScale(uint32_t format,
288 const HwcTestDim& dfMin, const HwcTestDim& dfMax,
289 const HwcTestDim& scMin, const HwcTestDim& scMax,
290 HwcTestDim& outBestDf, HwcTestDim& outBestSc);
291Rational scVScale(uint32_t format,
292 const HwcTestDim& dfMin, const HwcTestDim& dfMax,
293 const HwcTestDim& scMin, const HwcTestDim& scMax,
294 HwcTestDim& outBestDf, HwcTestDim& outBestSc);
295string transformList2str(const list<uint32_t>& transformList);
296string blendList2str(const list<uint32_t>& blendList);
297void init(void);
298void printSyntax(const char *cmd);
299
300// Command-line option settings
301static bool verbose = defaultVerbose;
302static HwcTestDim startDim = defaultStartDim;
303
304/*
305 * Main
306 *
307 * Performs the following high-level sequence of operations:
308 *
309 * 1. Command-line parsing
310 *
311 * 2. Form a list of command-line specified graphic formats. If
312 * no formats are specified, then form a list of all known formats.
313 *
314 * 3. Stop framework
315 * Only one user at a time is allowed to use the HWC. Surface
316 * Flinger uses the HWC and is part of the framework. Need to
317 * stop the framework so that Surface Flinger will stop using
318 * the HWC.
319 *
320 * 4. Initialization
321 *
322 * 5. For each graphic format in the previously formed list perform
323 * measurements on that format and report the results.
324 *
325 * 6. Start framework
326 */
327int
328main(int argc, char *argv[])
329{
330 int rv, opt;
331 char *chptr;
332 bool error;
333 string str;
334 char cmd[MAXCMD];
335 list<string> formats;
336 list<Rectangle> rectList;
337
338 testSetLogCatTag(LOG_TAG);
339
340 // Parse command line arguments
341 while ((opt = getopt(argc, argv, "s:v?h")) != -1) {
342 switch (opt) {
343
344 case 's': // Start Dimension
345 // Use arguments until next starts with a dash
346 // or current ends with a > or ]
347 str = optarg;
348 while (optind < argc) {
349 if (*argv[optind] == '-') { break; }
350 char endChar = (str.length() > 1) ? str[str.length() - 1] : 0;
351 if ((endChar == '>') || (endChar == ']')) { break; }
352 str += " " + string(argv[optind++]);
353 }
354 {
355 istringstream in(str);
356 startDim = hwcTestParseDim(in, error);
357 // Any parse error or characters not used by parser
358 if (error
359 || (((unsigned int) in.tellg() != in.str().length())
360 && (in.tellg() != (streampos) -1))) {
361 testPrintE("Invalid command-line specified start "
362 "dimension of: %s", str.c_str());
363 exit(8);
364 }
365 }
366 break;
367
368 case 'v': // Verbose
369 verbose = true;
370 break;
371
372 case 'h': // Help
373 case '?':
374 default:
375 printSyntax(basename(argv[0]));
376 exit(((optopt == 0) || (optopt == '?')) ? 0 : 11);
377 }
378 }
379
380 // Positional parameters
381 // Positional parameters provide the names of graphic formats that
382 // measurements are to be made on. Measurements are made on all
383 // known graphic formats when no positional parameters are provided.
384 if (optind == argc) {
385 // No command-line specified graphic formats
386 // Add all graphic formats to the list of formats to be measured
387 for (unsigned int n1 = 0; n1 < NUMA(hwcTestGraphicFormat); n1++) {
388 formats.push_back(hwcTestGraphicFormat[n1].desc);
389 }
390 } else {
391 // Add names of command-line specified graphic formats to the
392 // list of formats to be tested
393 for (; argv[optind] != NULL; optind++) {
394 formats.push_back(argv[optind]);
395 }
396 }
397
398 // Stop framework
399 rv = snprintf(cmd, sizeof(cmd), "%s", CMD_STOP_FRAMEWORK);
400 if (rv >= (signed) sizeof(cmd) - 1) {
401 testPrintE("Command too long for: %s", CMD_STOP_FRAMEWORK);
402 exit(14);
403 }
404 testExecCmd(cmd);
405 testDelay(1.0); // TODO - needs means to query whether asynchronous stop
406 // framework operation has completed. For now, just wait
407 // a long time.
408
409 testPrintI("startDim: %s", ((string) startDim).c_str());
410
411 init();
412
413 // For each of the graphic formats
414 for (list<string>::iterator itFormat = formats.begin();
415 itFormat != formats.end(); ++itFormat) {
416
417 // Locate hwcTestLib structure that describes this format
418 const struct hwcTestGraphicFormat *format;
419 format = hwcTestGraphicFormatLookup((*itFormat).c_str());
420 if (format == NULL) {
421 testPrintE("Unknown graphic format of: %s", (*itFormat).c_str());
422 exit(1);
423 }
424
425 // Display format header
426 testPrintI("format: %s", format->desc);
427
428 // Create area to hold the measurements
429 struct meas meas;
430 struct meas *measPtr;
431 meas.format = format->format;
432 measurements.push_back(meas);
433 measPtr = &measurements[measurements.size() - 1];
434
435 // Start dimension num overlays
436 Rectangle rect(format->format, startDim);
437 rectList.clear();
438 rectList.push_back(rect);
439 measPtr->startDimOverlays = numOverlays(rectList);
440 testPrintI(" startDimOverlays: %u", measPtr->startDimOverlays);
441
442 // Skip the rest of the measurements, when the start dimension
443 // doesn't produce an overlay
444 if (measPtr->startDimOverlays == 0) { continue; }
445
446 // Max Overlays
447 measPtr->maxNonOverlapping = maxOverlays(format->format, false);
448 testPrintI(" max nonOverlapping overlays: %s%u",
449 (measPtr->maxNonOverlapping == searchLimits.numOverlays)
450 ? ">= " : "",
451 measPtr->maxNonOverlapping);
452 measPtr->maxOverlapping = maxOverlays(format->format, true);
453 testPrintI(" max Overlapping overlays: %s%u",
454 (measPtr->maxOverlapping == searchLimits.numOverlays)
455 ? ">= " : "",
456 measPtr->maxOverlapping);
457
458 // Transforms and blends
459 measPtr->transforms = supportedTransforms(format->format);
460 testPrintI(" transforms: %s",
461 transformList2str(measPtr->transforms).c_str());
462 measPtr->blends = supportedBlends(format->format);
463 testPrintI(" blends: %s",
464 blendList2str(measPtr->blends).c_str());
465
466 // Display frame measurements
467 measPtr->df.minWidth = dfMinWidth(format->format);
468 testPrintI(" dfMinWidth: %u", measPtr->df.minWidth);
469
470 measPtr->df.minHeight = dfMinHeight(format->format);
471 testPrintI(" dfMinHeight: %u", measPtr->df.minHeight);
472
473 measPtr->df.maxWidth = dfMaxWidth(format->format);
474 testPrintI(" dfMaxWidth: %u", measPtr->df.maxWidth);
475
476 measPtr->df.maxHeight = dfMaxHeight(format->format);
477 testPrintI(" dfMaxHeight: %u", measPtr->df.maxHeight);
478
479 measPtr->df.minDim = dfMinDim(format->format);
480 testPrintI(" dfMinDim: %s", ((string) measPtr->df.minDim).c_str());
481
482 measPtr->df.maxDim = dfMaxDim(format->format);
483 testPrintI(" dfMaxDim: %s", ((string) measPtr->df.maxDim).c_str());
484
485 // Source crop measurements
486 measPtr->sc.minWidth = scMinWidth(format->format, measPtr->df.minDim);
487 testPrintI(" scMinWidth: %u", measPtr->sc.minWidth);
488
489 measPtr->sc.minHeight = scMinHeight(format->format, measPtr->df.minDim);
490 testPrintI(" scMinHeight: %u", measPtr->sc.minHeight);
491
492 measPtr->sc.maxWidth = scMaxWidth(format->format, measPtr->df.maxDim);
493 testPrintI(" scMaxWidth: %s%u", (measPtr->sc.maxWidth
494 == searchLimits.sourceCrop.width()) ? ">= " : "",
495 measPtr->sc.maxWidth);
496
497 measPtr->sc.maxHeight = scMaxHeight(format->format, measPtr->df.maxDim);
498 testPrintI(" scMaxHeight: %s%u", (measPtr->sc.maxHeight
499 == searchLimits.sourceCrop.height()) ? ">= " : "",
500 measPtr->sc.maxHeight);
501
502 measPtr->sc.minDim = scMinDim(format->format, measPtr->df.minDim);
503 testPrintI(" scMinDim: %s", ((string) measPtr->sc.minDim).c_str());
504
505 measPtr->sc.maxDim = scMaxDim(format->format, measPtr->df.maxDim);
506 testPrintI(" scMaxDim: %s%s", ((measPtr->sc.maxDim.width()
507 >= searchLimits.sourceCrop.width())
508 || (measPtr->sc.maxDim.width() >=
509 searchLimits.sourceCrop.height())) ? ">= " : "",
510 ((string) measPtr->sc.maxDim).c_str());
511
512 measPtr->sc.hScale = scHScale(format->format,
513 measPtr->df.minDim, measPtr->df.maxDim,
514 measPtr->sc.minDim, measPtr->sc.maxDim,
515 measPtr->sc.hScaleBestDf,
516 measPtr->sc.hScaleBestSc);
517 testPrintI(" scHScale: %s%f",
518 (measPtr->sc.hScale
519 >= Rational(searchLimits.sourceCrop.width(),
520 measPtr->df.minDim.width())) ? ">= " : "",
521 (double) measPtr->sc.hScale);
522 testPrintI(" HScale Best Display Frame: %s",
523 ((string) measPtr->sc.hScaleBestDf).c_str());
524 testPrintI(" HScale Best Source Crop: %s",
525 ((string) measPtr->sc.hScaleBestSc).c_str());
526
527 measPtr->sc.vScale = scVScale(format->format,
528 measPtr->df.minDim, measPtr->df.maxDim,
529 measPtr->sc.minDim, measPtr->sc.maxDim,
530 measPtr->sc.vScaleBestDf,
531 measPtr->sc.vScaleBestSc);
532 testPrintI(" scVScale: %s%f",
533 (measPtr->sc.vScale
534 >= Rational(searchLimits.sourceCrop.height(),
535 measPtr->df.minDim.height())) ? ">= " : "",
536 (double) measPtr->sc.vScale);
537 testPrintI(" VScale Best Display Frame: %s",
538 ((string) measPtr->sc.vScaleBestDf).c_str());
539 testPrintI(" VScale Best Source Crop: %s",
540 ((string) measPtr->sc.vScaleBestSc).c_str());
541
542 }
543
544 // Start framework
545 rv = snprintf(cmd, sizeof(cmd), "%s", CMD_START_FRAMEWORK);
546 if (rv >= (signed) sizeof(cmd) - 1) {
547 testPrintE("Command too long for: %s", CMD_START_FRAMEWORK);
548 exit(21);
549 }
550 testExecCmd(cmd);
551
552 return 0;
553}
554
555// Determine the maximum number of overlays that are all of the same format
556// that the HWC will commit to. If allowOverlap is true, then the rectangles
557// are laid out on a diagonal starting from the upper left corner. With
558// each rectangle adjust one pixel to the right and one pixel down.
559// When allowOverlap is false, the rectangles are tiled in column major
560// order. Note, column major ordering is used so that the initial rectangles
561// are all on different horizontal scan rows. It is common that hardware
562// has limits on the number of objects it can handle on any single row.
563uint32_t maxOverlays(uint32_t format, bool allowOverlap)
564{
565 unsigned int max = 0;
566
567 for (unsigned int numRects = 1; numRects <= searchLimits.numOverlays;
568 numRects++) {
569 list<Rectangle> rectList;
570
571 for (unsigned int x = 0;
572 (x + startDim.width()) < (unsigned int) width;
573 x += (allowOverlap) ? 1 : startDim.width()) {
574 for (unsigned int y = 0;
575 (y + startDim.height()) < (unsigned int) height;
576 y += (allowOverlap) ? 1 : startDim.height()) {
577 Rectangle rect(format, startDim, startDim);
578 rect.displayFrame.left = x;
579 rect.displayFrame.top = y;
580 rect.displayFrame.right = x + startDim.width();
581 rect.displayFrame.bottom = y + startDim.height();
582
583 rectList.push_back(rect);
584
585 if (rectList.size() >= numRects) { break; }
586 }
587 if (rectList.size() >= numRects) { break; }
588 }
589
590 uint32_t num = numOverlays(rectList);
591 if (num > max) { max = num; }
592 }
593
594 return max;
595}
596
597// Measures what transforms (i.e. flip horizontal, rotate 180) are
598// supported by the specified format
599list<uint32_t> supportedTransforms(uint32_t format)
600{
601 list<uint32_t> rv;
602 list<Rectangle> rectList;
603 Rectangle rect(format, startDim);
604
605 // For each of the transform types
606 for (unsigned int idx = 0; idx < NUMA(transformType); idx++) {
607 unsigned int id = transformType[idx].id;
608
609 rect.transform = id;
610 rectList.clear();
611 rectList.push_back(rect);
612 uint32_t num = numOverlays(rectList);
613
614 if (num == 1) {
615 rv.push_back(id);
616 }
617 }
618
619 return rv;
620}
621
622// Determines which types of blends (i.e. none, premult, coverage) are
623// supported by the specified format
624list<uint32_t> supportedBlends(uint32_t format)
625{
626 list<uint32_t> rv;
627 list<Rectangle> rectList;
628 Rectangle rect(format, startDim);
629
630 // For each of the blend types
631 for (unsigned int idx = 0; idx < NUMA(blendType); idx++) {
632 unsigned int id = blendType[idx].id;
633
634 rect.blend = id;
635 rectList.clear();
636 rectList.push_back(rect);
637 uint32_t num = numOverlays(rectList);
638
639 if (num == 1) {
640 rv.push_back(id);
641 }
642 }
643
644 return rv;
645}
646
647// Determines the minimum width of any display frame of the given format
648// that the HWC will commit to.
649uint32_t dfMinWidth(uint32_t format)
650{
651 uint32_t w;
652 list<Rectangle> rectList;
653
654 for (w = 1; w <= startDim.width(); w++) {
655 HwcTestDim dim(w, startDim.height());
656 Rectangle rect(format, dim);
657 rectList.clear();
658 rectList.push_back(rect);
659 uint32_t num = numOverlays(rectList);
660 if (num > 0) {
661 return w;
662 }
663 }
664 if (w > startDim.width()) {
665 testPrintE("Failed to locate display frame min width");
666 exit(33);
667 }
668
669 return w;
670}
671
672// Display frame minimum height
673uint32_t dfMinHeight(uint32_t format)
674{
675 uint32_t h;
676 list<Rectangle> rectList;
677
678 for (h = 1; h <= startDim.height(); h++) {
679 HwcTestDim dim(startDim.width(), h);
680 Rectangle rect(format, dim);
681 rectList.clear();
682 rectList.push_back(rect);
683 uint32_t num = numOverlays(rectList);
684 if (num > 0) {
685 return h;
686 }
687 }
688 if (h > startDim.height()) {
689 testPrintE("Failed to locate display frame min height");
690 exit(34);
691 }
692
693 return h;
694}
695
696// Display frame maximum width
697uint32_t dfMaxWidth(uint32_t format)
698{
699 uint32_t w;
700 list<Rectangle> rectList;
701
702 for (w = width; w >= startDim.width(); w--) {
703 HwcTestDim dim(w, startDim.height());
704 Rectangle rect(format, dim);
705 rectList.clear();
706 rectList.push_back(rect);
707 uint32_t num = numOverlays(rectList);
708 if (num > 0) {
709 return w;
710 }
711 }
712 if (w < startDim.width()) {
713 testPrintE("Failed to locate display frame max width");
714 exit(35);
715 }
716
717 return w;
718}
719
720// Display frame maximum height
721uint32_t dfMaxHeight(uint32_t format)
722{
723 uint32_t h;
724
725 for (h = height; h >= startDim.height(); h--) {
726 HwcTestDim dim(startDim.width(), h);
727 Rectangle rect(format, dim);
728 list<Rectangle> rectList;
729 rectList.push_back(rect);
730 uint32_t num = numOverlays(rectList);
731 if (num > 0) {
732 return h;
733 }
734 }
735 if (h < startDim.height()) {
736 testPrintE("Failed to locate display frame max height");
737 exit(36);
738 }
739
740 return h;
741}
742
743// Determine the minimum number of pixels that the HWC will ever commit to.
744// Note, this might be different that dfMinWidth * dfMinHeight, in that this
745// function adjusts both the width and height from the starting dimension.
746HwcTestDim dfMinDim(uint32_t format)
747{
748 uint64_t bestMinPixels = 0;
749 HwcTestDim bestDim;
750 bool bestSet = false; // True when value has been assigned to
751 // bestMinPixels and bestDim
752
753 bool origVerbose = verbose; // Temporarily turn off verbose
754 verbose = false;
755 for (uint32_t w = 1; w <= startDim.width(); w++) {
756 for (uint32_t h = 1; h <= startDim.height(); h++) {
757 if (bestSet && ((w > bestMinPixels) || (h > bestMinPixels))) {
758 break;
759 }
760
761 HwcTestDim dim(w, h);
762 Rectangle rect(format, dim);
763 list<Rectangle> rectList;
764 rectList.push_back(rect);
765 uint32_t num = numOverlays(rectList);
766 if (num > 0) {
767 uint64_t pixels = dim.width() * dim.height();
768 if (!bestSet || (pixels < bestMinPixels)) {
769 bestMinPixels = pixels;
770 bestDim = dim;
771 bestSet = true;
772 }
773 }
774 }
775 }
776 verbose = origVerbose;
777
778 if (!bestSet) {
779 testPrintE("Unable to locate display frame min dimension");
780 exit(20);
781 }
782
783 return bestDim;
784}
785
786// Display frame maximum dimension
787HwcTestDim dfMaxDim(uint32_t format)
788{
789 uint64_t bestMaxPixels = 0;
790 HwcTestDim bestDim;
791 bool bestSet = false; // True when value has been assigned to
792 // bestMaxPixels and bestDim;
793
794 // Potentially increase benchmark performance by first checking
795 // for the common case of supporting a full display frame.
796 HwcTestDim dim(width, height);
797 Rectangle rect(format, dim);
798 list<Rectangle> rectList;
799 rectList.push_back(rect);
800 uint32_t num = numOverlays(rectList);
801 if (num == 1) { return dim; }
802
803 // TODO: Use a binary search
804 bool origVerbose = verbose; // Temporarily turn off verbose
805 verbose = false;
806 for (uint32_t w = startDim.width(); w <= (uint32_t) width; w++) {
807 for (uint32_t h = startDim.height(); h <= (uint32_t) height; h++) {
808 if (bestSet && ((w * h) <= bestMaxPixels)) { continue; }
809
810 HwcTestDim dim(w, h);
811 Rectangle rect(format, dim);
812 list<Rectangle> rectList;
813 rectList.push_back(rect);
814 uint32_t num = numOverlays(rectList);
815 if (num > 0) {
816 uint64_t pixels = dim.width() * dim.height();
817 if (!bestSet || (pixels > bestMaxPixels)) {
818 bestMaxPixels = pixels;
819 bestDim = dim;
820 bestSet = true;
821 }
822 }
823 }
824 }
825 verbose = origVerbose;
826
827 if (!bestSet) {
828 testPrintE("Unable to locate display frame max dimension");
829 exit(21);
830 }
831
832 return bestDim;
833}
834
835// Source crop minimum width
836uint32_t scMinWidth(uint32_t format, const HwcTestDim& dfDim)
837{
838 uint32_t w;
839 list<Rectangle> rectList;
840
841 // Source crop frame min width
842 for (w = 1; w <= dfDim.width(); w++) {
843 Rectangle rect(format, dfDim, HwcTestDim(w, dfDim.height()));
844 rectList.clear();
845 rectList.push_back(rect);
846 uint32_t num = numOverlays(rectList);
847 if (num > 0) {
848 return w;
849 }
850 }
851 testPrintE("Failed to locate source crop min width");
852 exit(35);
853}
854
855// Source crop minimum height
856uint32_t scMinHeight(uint32_t format, const HwcTestDim& dfDim)
857{
858 uint32_t h;
859 list<Rectangle> rectList;
860
861 for (h = 1; h <= dfDim.height(); h++) {
862 Rectangle rect(format, dfDim, HwcTestDim(dfDim.width(), h));
863 rectList.clear();
864 rectList.push_back(rect);
865 uint32_t num = numOverlays(rectList);
866 if (num > 0) {
867 return h;
868 }
869 }
870 testPrintE("Failed to locate source crop min height");
871 exit(36);
872}
873
874// Source crop maximum width
875uint32_t scMaxWidth(uint32_t format, const HwcTestDim& dfDim)
876{
877 uint32_t w;
878 list<Rectangle> rectList;
879
880 for (w = searchLimits.sourceCrop.width(); w >= dfDim.width(); w--) {
881 Rectangle rect(format, dfDim, HwcTestDim(w, dfDim.height()));
882 rectList.clear();
883 rectList.push_back(rect);
884 uint32_t num = numOverlays(rectList);
885 if (num > 0) {
886 return w;
887 }
888 }
889 testPrintE("Failed to locate source crop max width");
890 exit(35);
891}
892
893// Source crop maximum height
894uint32_t scMaxHeight(uint32_t format, const HwcTestDim& dfDim)
895{
896 uint32_t h;
897 list<Rectangle> rectList;
898
899 for (h = searchLimits.sourceCrop.height(); h >= dfDim.height(); h--) {
900 Rectangle rect(format, dfDim, HwcTestDim(dfDim.width(), h));
901 rectList.clear();
902 rectList.push_back(rect);
903 uint32_t num = numOverlays(rectList);
904 if (num > 0) {
905 return h;
906 }
907 }
908 testPrintE("Failed to locate source crop max height");
909 exit(36);
910}
911
912// Source crop minimum dimension
913// Discovers the source crop with the least number of pixels that the
914// HWC will commit to. Note, this may be different from scMinWidth
915// * scMinHeight, in that this function searches for a combination of
916// width and height. While the other routines always keep one of the
917// dimensions equal to the corresponding start dimension.
918HwcTestDim scMinDim(uint32_t format, const HwcTestDim& dfDim)
919{
920 uint64_t bestMinPixels = 0;
921 HwcTestDim bestDim;
922 bool bestSet = false; // True when value has been assigned to
923 // bestMinPixels and bestDim
924
925 bool origVerbose = verbose; // Temporarily turn off verbose
926 verbose = false;
927 for (uint32_t w = 1; w <= dfDim.width(); w++) {
928 for (uint32_t h = 1; h <= dfDim.height(); h++) {
929 if (bestSet && ((w > bestMinPixels) || (h > bestMinPixels))) {
930 break;
931 }
932
933 HwcTestDim dim(w, h);
934 Rectangle rect(format, dfDim, HwcTestDim(w, h));
935 list<Rectangle> rectList;
936 rectList.push_back(rect);
937 uint32_t num = numOverlays(rectList);
938 if (num > 0) {
939 uint64_t pixels = dim.width() * dim.height();
940 if (!bestSet || (pixels < bestMinPixels)) {
941 bestMinPixels = pixels;
942 bestDim = dim;
943 bestSet = true;
944 }
945 }
946 }
947 }
948 verbose = origVerbose;
949
950 if (!bestSet) {
951 testPrintE("Unable to locate source crop min dimension");
952 exit(20);
953 }
954
955 return bestDim;
956}
957
958// Source crop maximum dimension
959HwcTestDim scMaxDim(uint32_t format, const HwcTestDim& dfDim)
960{
961 uint64_t bestMaxPixels = 0;
962 HwcTestDim bestDim;
963 bool bestSet = false; // True when value has been assigned to
964 // bestMaxPixels and bestDim;
965
966 // Potentially increase benchmark performance by first checking
967 // for the common case of supporting the maximum checked source size
968 HwcTestDim dim = searchLimits.sourceCrop;
969 Rectangle rect(format, dfDim, searchLimits.sourceCrop);
970 list<Rectangle> rectList;
971 rectList.push_back(rect);
972 uint32_t num = numOverlays(rectList);
973 if (num == 1) { return dim; }
974
975 // TODO: Use a binary search
976 bool origVerbose = verbose; // Temporarily turn off verbose
977 verbose = false;
978 for (uint32_t w = dfDim.width();
979 w <= searchLimits.sourceCrop.width(); w++) {
980 for (uint32_t h = dfDim.height();
981 h <= searchLimits.sourceCrop.height(); h++) {
982 if (bestSet && ((w * h) <= bestMaxPixels)) { continue; }
983
984 HwcTestDim dim(w, h);
985 Rectangle rect(format, dfDim, dim);
986 list<Rectangle> rectList;
987 rectList.push_back(rect);
988 uint32_t num = numOverlays(rectList);
989 if (num > 0) {
990 uint64_t pixels = dim.width() * dim.height();
991 if (!bestSet || (pixels > bestMaxPixels)) {
992 bestMaxPixels = pixels;
993 bestDim = dim;
994 bestSet = true;
995 }
996 }
997 }
998 }
999 verbose = origVerbose;
1000
1001 if (!bestSet) {
1002 testPrintE("Unable to locate source crop max dimension");
1003 exit(21);
1004 }
1005
1006 return bestDim;
1007}
1008
1009// Source crop horizontal scale
1010// Determines the maximum factor by which the source crop can be larger
1011// that the display frame. The commit point is discovered through a
1012// binary search of rational numbers. The numerator in each of the
1013// rational numbers contains the dimension for the source crop, while
1014// the denominator specifies the dimension for the display frame. On
1015// each pass of the binary search the mid-point between the greatest
1016// point committed to (best) and the smallest point in which a commit
1017// has failed is calculated. This mid-point is then passed to a function
1018// named double2Rational, which determines the closest rational numbers
1019// just below and above the mid-point. By default the lower rational
1020// number is used for the scale factor on the next pass of the binary
1021// search. The upper value is only used when best is already equal
1022// to the lower value. This only occurs when the lower value has already
1023// been tried.
1024Rational scHScale(uint32_t format,
1025 const HwcTestDim& dfMin, const HwcTestDim& dfMax,
1026 const HwcTestDim& scMin, const HwcTestDim& scMax,
1027 HwcTestDim& outBestDf, HwcTestDim& outBestSc)
1028{
1029 HwcTestDim scDim, dfDim; // Source crop and display frame dimension
1030 Rational best(0, 1), minBad; // Current bounds for a binary search
1031 // MinGood is set below the lowest
1032 // possible scale. The value of minBad,
1033 // will be set by the first pass
1034 // of the binary search.
1035
1036 // Perform the passes of the binary search
1037 bool firstPass = true;
1038 do {
1039 // On first pass try the maximum scale within the search limits
1040 if (firstPass) {
1041 // Try the maximum possible scale, within the search limits
1042 scDim = HwcTestDim(searchLimits.sourceCrop.width(), scMin.height());
1043 dfDim = dfMin;
1044 } else {
1045 // Subsequent pass
1046 // Halve the difference between best and minBad.
1047 Rational lower, upper, selected;
1048
1049 // Try the closest ratio halfway between minBood and minBad;
1050 // TODO: Avoid rounding issue by using Rational type for
1051 // midpoint. For now will use double, which should
1052 // have more than sufficient resolution.
1053 double mid = (double) best
1054 + ((double) minBad - (double) best) / 2.0;
1055 Rational::double2Rational(mid,
1056 Range(scMin.width(), scMax.width()),
1057 Range(dfMin.width(), dfMax.width()),
1058 lower, upper);
1059 if (((lower == best) && (upper == minBad))) {
1060 return best;
1061 }
1062
1063 // Use lower value unless its already been tried
1064 selected = (lower != best) ? lower : upper;
1065
1066 // Assign the size of the source crop and display frame
1067 // from the selected ratio of source crop to display frame.
1068 scDim = HwcTestDim(selected.numerator(), scMin.height());
1069 dfDim = HwcTestDim(selected.denominator(), dfMin.height());
1070 }
1071
1072 // See if the HWC will commit to this combination
1073 Rectangle rect(format, dfDim, scDim);
1074 list<Rectangle> rectList;
1075 rectList.push_back(rect);
1076 uint32_t num = numOverlays(rectList);
1077
1078 if (verbose) {
1079 testPrintI(" scHscale num: %u scale: %f dfDim: %s scDim: %s",
1080 num, (float) Rational(scDim.width(), dfDim.width()),
1081 ((string) dfDim).c_str(), ((string) scDim).c_str());
1082 }
1083 if (num == 1) {
1084 // HWC committed to the combination
1085 // This is the best scale factor seen so far. Report the
1086 // dimensions to the caller, in case nothing better is seen.
1087 outBestDf = dfDim;
1088 outBestSc = scDim;
1089
1090 // Success on the first pass means the largest possible scale
1091 // is supported, in which case no need to search any further.
1092 if (firstPass) { return Rational(scDim.width(), dfDim.width()); }
1093
1094 // Update the lower bound of the binary search
1095 best = Rational(scDim.width(), dfDim.width());
1096 } else {
1097 // HWC didn't commit to this combination, so update the
1098 // upper bound of the binary search.
1099 minBad = Rational(scDim.width(), dfDim.width());
1100 }
1101
1102 firstPass = false;
1103 } while (best != minBad);
1104
1105 return best;
1106}
1107
1108// Source crop vertical scale
1109// Determines the maximum factor by which the source crop can be larger
1110// that the display frame. The commit point is discovered through a
1111// binary search of rational numbers. The numerator in each of the
1112// rational numbers contains the dimension for the source crop, while
1113// the denominator specifies the dimension for the display frame. On
1114// each pass of the binary search the mid-point between the greatest
1115// point committed to (best) and the smallest point in which a commit
1116// has failed is calculated. This mid-point is then passed to a function
1117// named double2Rational, which determines the closest rational numbers
1118// just below and above the mid-point. By default the lower rational
1119// number is used for the scale factor on the next pass of the binary
1120// search. The upper value is only used when best is already equal
1121// to the lower value. This only occurs when the lower value has already
1122// been tried.
1123Rational scVScale(uint32_t format,
1124 const HwcTestDim& dfMin, const HwcTestDim& dfMax,
1125 const HwcTestDim& scMin, const HwcTestDim& scMax,
1126 HwcTestDim& outBestDf, HwcTestDim& outBestSc)
1127{
1128 HwcTestDim scDim, dfDim; // Source crop and display frame dimension
1129 Rational best(0, 1), minBad; // Current bounds for a binary search
1130 // MinGood is set below the lowest
1131 // possible scale. The value of minBad,
1132 // will be set by the first pass
1133 // of the binary search.
1134
1135 // Perform the passes of the binary search
1136 bool firstPass = true;
1137 do {
1138 // On first pass try the maximum scale within the search limits
1139 if (firstPass) {
1140 // Try the maximum possible scale, within the search limits
1141 scDim = HwcTestDim(scMin.width(), searchLimits.sourceCrop.height());
1142 dfDim = dfMin;
1143 } else {
1144 // Subsequent pass
1145 // Halve the difference between best and minBad.
1146 Rational lower, upper, selected;
1147
1148 // Try the closest ratio halfway between minBood and minBad;
1149 // TODO: Avoid rounding issue by using Rational type for
1150 // midpoint. For now will use double, which should
1151 // have more than sufficient resolution.
1152 double mid = (double) best
1153 + ((double) minBad - (double) best) / 2.0;
1154 Rational::double2Rational(mid,
1155 Range(scMin.height(), scMax.height()),
1156 Range(dfMin.height(), dfMax.height()),
1157 lower, upper);
1158 if (((lower == best) && (upper == minBad))) {
1159 return best;
1160 }
1161
1162 // Use lower value unless its already been tried
1163 selected = (lower != best) ? lower : upper;
1164
1165 // Assign the size of the source crop and display frame
1166 // from the selected ratio of source crop to display frame.
1167 scDim = HwcTestDim(scMin.width(), selected.numerator());
1168 dfDim = HwcTestDim(dfMin.width(), selected.denominator());
1169 }
1170
1171 // See if the HWC will commit to this combination
1172 Rectangle rect(format, dfDim, scDim);
1173 list<Rectangle> rectList;
1174 rectList.push_back(rect);
1175 uint32_t num = numOverlays(rectList);
1176
1177 if (verbose) {
1178 testPrintI(" scHscale num: %u scale: %f dfDim: %s scDim: %s",
1179 num, (float) Rational(scDim.height(), dfDim.height()),
1180 ((string) dfDim).c_str(), ((string) scDim).c_str());
1181 }
1182 if (num == 1) {
1183 // HWC committed to the combination
1184 // This is the best scale factor seen so far. Report the
1185 // dimensions to the caller, in case nothing better is seen.
1186 outBestDf = dfDim;
1187 outBestSc = scDim;
1188
1189 // Success on the first pass means the largest possible scale
1190 // is supported, in which case no need to search any further.
1191 if (firstPass) { return Rational(scDim.height(), dfDim.height()); }
1192
1193 // Update the lower bound of the binary search
1194 best = Rational(scDim.height(), dfDim.height());
1195 } else {
1196 // HWC didn't commit to this combination, so update the
1197 // upper bound of the binary search.
1198 minBad = Rational(scDim.height(), dfDim.height());
1199 }
1200
1201 firstPass = false;
1202 } while (best != minBad);
1203
1204 return best;
1205}
1206
1207Rectangle::Rectangle(uint32_t graphicFormat, HwcTestDim dfDim,
1208 HwcTestDim sDim) :
1209 format(graphicFormat), transform(defaultTransform),
1210 blend(defaultBlend), color(defaultColor), alpha(defaultAlpha),
1211 sourceCrop(sDim), displayFrame(dfDim)
1212{
1213 // Set source dimension
1214 // Can't use a base initializer, because the setting of format
1215 // must be done before setting the sourceDimension.
1216 setSourceDim(sDim);
1217}
1218
1219void Rectangle::setSourceDim(HwcTestDim dim)
1220{
1221 this->sourceDim = dim;
1222
1223 const struct hwcTestGraphicFormat *attrib;
1224 attrib = hwcTestGraphicFormatLookup(this->format);
1225 if (attrib != NULL) {
1226 if (sourceDim.width() % attrib->wMod) {
1227 sourceDim.setWidth(sourceDim.width() + attrib->wMod
1228 - (sourceDim.width() % attrib->wMod));
1229 }
1230 if (sourceDim.height() % attrib->hMod) {
1231 sourceDim.setHeight(sourceDim.height() + attrib->hMod
1232 - (sourceDim.height() % attrib->hMod));
1233 }
1234 }
1235}
1236
1237// Rational member functions
1238bool Rational::operator==(const Rational& other) const
1239{
1240 if (((uint64_t) _n * other._d)
1241 == ((uint64_t) _d * other._n)) { return true; }
1242
1243 return false;
1244}
1245
1246bool Rational::operator<(const Rational& other) const
1247{
1248 if (((uint64_t) _n * other._d)
1249 < ((uint64_t) _d * other._n)) { return true; }
1250
1251 return false;
1252}
1253
1254Rational::operator string() const
1255{
1256 ostringstream out;
1257
1258 out << _n << '/' << _d;
1259
1260 return out.str();
1261}
1262
1263void Rational::double2Rational(double f, Range nRange, Range dRange,
1264 Rational& lower, Rational& upper)
1265{
1266 Rational bestLower(nRange.lower(), dRange.upper());
1267 Rational bestUpper(nRange.upper(), dRange.lower());
1268
1269 // Search for a better solution
1270 for (uint32_t d = dRange.lower(); d <= dRange.upper(); d++) {
1271 Rational val(d * f, d); // Lower, because double to int cast truncates
1272
1273 if ((val.numerator() < nRange.lower())
1274 || (val.numerator() > nRange.upper())) { continue; }
1275
1276 if (((double) val > (double) bestLower) && ((double) val <= f)) {
1277 bestLower = val;
1278 }
1279
1280 val.setNumerator(val.numerator() + 1);
1281 if (val.numerator() > nRange.upper()) { continue; }
1282
1283 if (((double) val < (double) bestUpper) && ((double) val >= f)) {
1284 bestUpper = val;
1285 }
1286 }
1287
1288 lower = bestLower;
1289 upper = bestUpper;
1290}
1291
1292// Local functions
1293
1294// Num Overlays
1295// Given a list of rectangles, determine how many HWC will commit to render
1296uint32_t numOverlays(list<Rectangle>& rectList)
1297{
1298 hwc_layer_list_t *hwcList;
1299 list<sp<GraphicBuffer> > buffers;
1300
1301 hwcList = hwcTestCreateLayerList(rectList.size());
1302 if (hwcList == NULL) {
1303 testPrintE("numOverlays create hwcList failed");
1304 exit(30);
1305 }
1306
1307 hwc_layer_t *layer = &hwcList->hwLayers[0];
1308 for (std::list<Rectangle>::iterator it = rectList.begin();
1309 it != rectList.end(); ++it, ++layer) {
1310 // Allocate the texture for the source frame
1311 // and push it onto the buffers list, so that it
1312 // stays in scope until a return from this function.
1313 sp<GraphicBuffer> texture;
1314 texture = new GraphicBuffer(it->sourceDim.width(),
1315 it->sourceDim.height(),
1316 it->format, texUsage);
1317 buffers.push_back(texture);
1318
1319 layer->handle = texture->handle;
1320 layer->blending = it->blend;
1321 layer->transform = it->transform;
1322 layer->sourceCrop = it->sourceCrop;
1323 layer->displayFrame = it->displayFrame;
1324
1325 layer->visibleRegionScreen.numRects = 1;
1326 layer->visibleRegionScreen.rects = &layer->displayFrame;
1327 }
1328
1329 // Perform prepare operation
1330 if (verbose) { testPrintI("Prepare:"); hwcTestDisplayList(hwcList); }
1331 hwcDevice->prepare(hwcDevice, hwcList);
1332 if (verbose) {
1333 testPrintI("Post Prepare:");
1334 hwcTestDisplayListPrepareModifiable(hwcList);
1335 }
1336
1337 // Count the number of overlays
1338 uint32_t total = 0;
1339 for (unsigned int n1 = 0; n1 < hwcList->numHwLayers; n1++) {
1340 if (hwcList->hwLayers[n1].compositionType == HWC_OVERLAY) {
1341 total++;
1342 }
1343 }
1344
1345 // Free the layer list and graphic buffers
1346 hwcTestFreeLayerList(hwcList);
1347
1348 return total;
1349}
1350
1351string transformList2str(const list<uint32_t>& transformList)
1352{
1353 ostringstream out;
1354
1355 for (list<uint32_t>::const_iterator it = transformList.begin();
1356 it != transformList.end(); ++it) {
1357 uint32_t id = *it;
1358
1359 if (it != transformList.begin()) {
1360 out << ", ";
1361 }
1362 out << id;
1363
1364 for (unsigned int idx = 0; idx < NUMA(transformType); idx++) {
1365 if (id == transformType[idx].id) {
1366 out << " (" << transformType[idx].desc << ')';
1367 break;
1368 }
1369 }
1370 }
1371
1372 return out.str();
1373}
1374
1375string blendList2str(const list<uint32_t>& blendList)
1376{
1377 ostringstream out;
1378
1379 for (list<uint32_t>::const_iterator it = blendList.begin();
1380 it != blendList.end(); ++it) {
1381 uint32_t id = *it;
1382
1383 if (it != blendList.begin()) {
1384 out << ", ";
1385 }
1386 out << id;
1387
1388 for (unsigned int idx = 0; idx < NUMA(blendType); idx++) {
1389 if (id == blendType[idx].id) {
1390 out << " (" << blendType[idx].desc << ')';
1391 break;
1392 }
1393 }
1394 }
1395
1396 return out.str();
1397}
1398
1399void init(void)
1400{
1401 srand48(0);
1402
1403 hwcTestInitDisplay(verbose, &dpy, &surface, &width, &height);
1404
1405 hwcTestOpenHwc(&hwcDevice);
1406}
1407
1408void printSyntax(const char *cmd)
1409{
1410 testPrintE(" %s [options] [graphicFormat] ...",
1411 cmd);
1412 testPrintE(" options:");
1413 testPrintE(" -s [width, height] - start dimension");
1414 testPrintE(" -v - Verbose");
1415 testPrintE("");
1416 testPrintE(" graphic formats:");
1417 for (unsigned int n1 = 0; n1 < NUMA(hwcTestGraphicFormat); n1++) {
1418 testPrintE(" %s", hwcTestGraphicFormat[n1].desc);
1419 }
1420}