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