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