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