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