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