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