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