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