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