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