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