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