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