Louis Huemiller | ec0da1a | 2011-01-05 18:53:47 -0800 | [diff] [blame] | 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 | * Hardware Composer Rectangles |
| 19 | * |
| 20 | * Synopsis |
| 21 | * hwcRects [options] (graphicFormat displayFrame [attributes],)... |
| 22 | * options: |
| 23 | * -D #.## - End of test delay |
Louis Huemiller | 585cd4f | 2011-01-09 10:59:31 -0800 | [diff] [blame] | 24 | * -v - Verbose |
Louis Huemiller | ec0da1a | 2011-01-05 18:53:47 -0800 | [diff] [blame] | 25 | * |
| 26 | * graphic formats: |
| 27 | * RGBA8888 (reference frame default) |
| 28 | * RGBX8888 |
| 29 | * RGB888 |
| 30 | * RGB565 |
| 31 | * BGRA8888 |
| 32 | * RGBA5551 |
| 33 | * RGBA4444 |
| 34 | * YV12 |
| 35 | * |
| 36 | * displayFrame |
| 37 | * [left, top, right, bottom] |
| 38 | * |
| 39 | * attributes: |
| 40 | * transform: none | fliph | flipv | rot90 | rot180 | rot270 |
| 41 | * blend: none | premult | coverage |
| 42 | * color: [0.##, 0.##, 0.##] |
| 43 | * alpha: 0.## |
| 44 | * sourceDim: [width, height] |
| 45 | * sourceCrop: [left, top, right, bottom] |
| 46 | * |
| 47 | * Example: |
| 48 | * # White YV12 rectangle, with overlapping turquoise |
| 49 | * # RGBA8888 rectangle at 30%% (alpha: 0.7) transparency |
| 50 | * hwcRects -v -D 30.0 \ |
| 51 | * YV12 [50, 80, 200, 300] transform: none \ |
| 52 | * color: [1.0, 0.5, 0.5], \ |
| 53 | * RGBA8888 [100, 150, 300, 400] blend: coverage \ |
| 54 | * color: [0.251, 0.878, 0.816] alpha: 0.7 \ |
| 55 | * sourceDim: [50, 60] sourceCrop: [5, 8, 12, 15] |
| 56 | * |
| 57 | * Description |
| 58 | * Constructs a Hardware Composer (HWC) list of frames from |
| 59 | * command-line specified parameters. Then sends it to the HWC |
| 60 | * be rendered. The intended purpose of this tool is as a means to |
| 61 | * reproduce and succinctly specify an observed HWC operation, with |
| 62 | * no need to modify/compile a program. |
| 63 | * |
| 64 | * The command-line syntax consists of a few standard command-line |
| 65 | * options and then a description of one or more frames. The frame |
| 66 | * descriptions are separated from one another via a comma. The |
| 67 | * beginning of a frame description requires the specification |
| 68 | * of the graphic format and then the display frame rectangle where |
| 69 | * the frame will be displayed. The display frame rectangle is |
| 70 | * specified as follows, with the right and bottom coordinates being |
| 71 | * exclusive values: |
| 72 | * |
| 73 | * [left, top, right, bottom] |
| 74 | * |
| 75 | * After these two required parameters each frame description can |
| 76 | * specify 1 or more optional attributes. The name of each optional |
| 77 | * attribute is preceded by a colon. The current implementation |
| 78 | * then requires white space after the colon and then the value of |
| 79 | * the attribute is specified. See the synopsis section above for |
| 80 | * a list of attributes and the format of their expected value. |
| 81 | */ |
| 82 | |
| 83 | #include <algorithm> |
| 84 | #include <assert.h> |
| 85 | #include <cerrno> |
| 86 | #include <cmath> |
| 87 | #include <cstdlib> |
| 88 | #include <ctime> |
| 89 | #include <istream> |
| 90 | #include <libgen.h> |
| 91 | #include <list> |
| 92 | #include <sched.h> |
| 93 | #include <sstream> |
| 94 | #include <stdint.h> |
| 95 | #include <string.h> |
| 96 | #include <unistd.h> |
| 97 | |
| 98 | #include <sys/syscall.h> |
| 99 | #include <sys/types.h> |
| 100 | #include <sys/wait.h> |
| 101 | |
| 102 | #include <EGL/egl.h> |
| 103 | #include <EGL/eglext.h> |
| 104 | #include <GLES2/gl2.h> |
| 105 | #include <GLES2/gl2ext.h> |
| 106 | |
| 107 | #include <ui/FramebufferNativeWindow.h> |
| 108 | #include <ui/GraphicBuffer.h> |
| 109 | #include <ui/EGLUtils.h> |
| 110 | |
Louis Huemiller | 585cd4f | 2011-01-09 10:59:31 -0800 | [diff] [blame] | 111 | #define LOG_TAG "hwcRectsTest" |
Louis Huemiller | ec0da1a | 2011-01-05 18:53:47 -0800 | [diff] [blame] | 112 | #include <utils/Log.h> |
| 113 | #include <testUtil.h> |
| 114 | |
| 115 | #include <hardware/hwcomposer.h> |
| 116 | |
| 117 | #include <glTestLib.h> |
| 118 | #include <hwc/hwcTestLib.h> |
| 119 | |
| 120 | using namespace std; |
| 121 | using namespace android; |
| 122 | |
| 123 | // Defaults |
| 124 | const bool defaultVerbose = false; |
| 125 | const float defaultEndDelay = 2.0; // Default delay after rendering graphics |
| 126 | |
| 127 | const uint32_t defaultFormat = HAL_PIXEL_FORMAT_RGBA_8888; |
| 128 | const int32_t defaultTransform = 0; |
| 129 | const uint32_t defaultBlend = HWC_BLENDING_NONE; |
| 130 | const ColorFract defaultColor(0.5, 0.5, 0.5); |
| 131 | const float defaultAlpha = 1.0; // Opaque |
| 132 | const HwcTestDim defaultSourceDim(1, 1); |
| 133 | const struct hwc_rect defaultSourceCrop = {0, 0, 1, 1}; |
| 134 | const struct hwc_rect defaultDisplayFrame = {0, 0, 100, 100}; |
| 135 | |
| 136 | // Defines |
| 137 | #define MAXCMD 200 |
| 138 | #define CMD_STOP_FRAMEWORK "stop 2>&1" |
| 139 | #define CMD_START_FRAMEWORK "start 2>&1" |
| 140 | |
| 141 | // Macros |
| 142 | #define NUMA(a) (sizeof(a) / sizeof(a [0])) // Num elements in an array |
| 143 | |
| 144 | // Local types |
| 145 | class Rectangle { |
| 146 | public: |
| 147 | Rectangle() : format(defaultFormat), transform(defaultTransform), |
| 148 | blend(defaultBlend), color(defaultColor), |
| 149 | alpha(defaultAlpha), sourceDim(defaultSourceDim), |
| 150 | sourceCrop(defaultSourceCrop), |
| 151 | displayFrame(defaultDisplayFrame) {}; |
| 152 | |
| 153 | uint32_t format; |
| 154 | uint32_t transform; |
| 155 | int32_t blend; |
| 156 | ColorFract color; |
| 157 | float alpha; |
| 158 | HwcTestDim sourceDim; |
| 159 | struct hwc_rect sourceCrop; |
| 160 | struct hwc_rect displayFrame; |
| 161 | |
| 162 | sp<GraphicBuffer> texture; |
| 163 | }; |
| 164 | |
| 165 | // Globals |
| 166 | list<Rectangle> rectangle; |
| 167 | static const int texUsage = GraphicBuffer::USAGE_HW_TEXTURE | |
| 168 | GraphicBuffer::USAGE_SW_WRITE_RARELY; |
| 169 | static hwc_composer_device_t *hwcDevice; |
| 170 | static EGLDisplay dpy; |
| 171 | static EGLSurface surface; |
| 172 | static EGLint width, height; |
| 173 | |
| 174 | // Function prototypes |
| 175 | static Rectangle parseRect(string rectStr); |
| 176 | void init(void); |
| 177 | void printSyntax(const char *cmd); |
| 178 | |
| 179 | // Command-line option settings |
| 180 | static bool verbose = defaultVerbose; |
| 181 | static float endDelay = defaultEndDelay; |
| 182 | |
| 183 | /* |
| 184 | * Main |
| 185 | * |
| 186 | * Performs the following high-level sequence of operations: |
| 187 | * |
| 188 | * 1. Parse command-line options |
| 189 | * |
| 190 | * 2. Stop framework |
| 191 | * |
| 192 | * 3. Initialization |
| 193 | * |
| 194 | * 4. Parse frame descriptions |
| 195 | * |
| 196 | * 5. Create HWC list from frame descriptions |
| 197 | * |
| 198 | * 6. Have HWC render the list description of the frames |
| 199 | * |
| 200 | * 7. Delay for amount of time given by endDelay |
| 201 | * |
| 202 | * 8. Start framework |
| 203 | */ |
| 204 | int |
| 205 | main(int argc, char *argv[]) |
| 206 | { |
| 207 | int rv, opt; |
| 208 | char *chptr; |
| 209 | bool error; |
| 210 | string str; |
| 211 | char cmd[MAXCMD]; |
| 212 | |
Louis Huemiller | 585cd4f | 2011-01-09 10:59:31 -0800 | [diff] [blame] | 213 | testSetLogCatTag(LOG_TAG); |
| 214 | |
Louis Huemiller | ec0da1a | 2011-01-05 18:53:47 -0800 | [diff] [blame] | 215 | // Parse command line arguments |
| 216 | while ((opt = getopt(argc, argv, "D:v?h")) != -1) { |
| 217 | switch (opt) { |
| 218 | case 'D': // End of test delay |
| 219 | endDelay = strtod(optarg, &chptr); |
| 220 | if ((*chptr != '\0') || (endDelay < 0.0)) { |
| 221 | testPrintE("Invalid command-line specified end of test delay " |
| 222 | "of: %s", optarg); |
| 223 | exit(1); |
| 224 | } |
| 225 | break; |
| 226 | |
| 227 | case 'v': // Verbose |
| 228 | verbose = true; |
| 229 | break; |
| 230 | |
| 231 | case 'h': // Help |
| 232 | case '?': |
| 233 | default: |
| 234 | printSyntax(basename(argv[0])); |
| 235 | exit(((optopt == 0) || (optopt == '?')) ? 0 : 2); |
| 236 | } |
| 237 | } |
| 238 | |
| 239 | // Stop framework |
| 240 | rv = snprintf(cmd, sizeof(cmd), "%s", CMD_STOP_FRAMEWORK); |
| 241 | if (rv >= (signed) sizeof(cmd) - 1) { |
| 242 | testPrintE("Command too long for: %s", CMD_STOP_FRAMEWORK); |
| 243 | exit(3); |
| 244 | } |
| 245 | testExecCmd(cmd); |
| 246 | testDelay(1.0); // TODO - needs means to query whether asyncronous stop |
| 247 | // framework operation has completed. For now, just wait |
| 248 | // a long time. |
| 249 | |
| 250 | init(); |
| 251 | |
| 252 | // Parse rectangle descriptions |
| 253 | int numOpen = 0; // Current number of unmatched <[ |
| 254 | string rectDesc(""); // String description of a single rectangle |
| 255 | while (optind < argc) { |
| 256 | string argNext = string(argv[optind++]); |
| 257 | |
| 258 | if (rectDesc.length()) { rectDesc += ' '; } |
| 259 | rectDesc += argNext; |
| 260 | |
| 261 | // Count number of opening <[ and matching >] |
| 262 | // At this point not worried about an opening character being |
| 263 | // matched by it's corresponding closing character. For example, |
| 264 | // "<1.0, 2.0]" is incorrect because the opening < should be matched |
| 265 | // with a closing >, instead of the closing ]. Such errors are |
| 266 | // detected when the actual value is parsed. |
| 267 | for (unsigned int n1 = 0; n1 < argNext.length(); n1++) { |
| 268 | switch(argNext[n1]) { |
| 269 | case '[': |
| 270 | case '<': |
| 271 | numOpen++; |
| 272 | break; |
| 273 | |
| 274 | case ']': |
| 275 | case '>': |
| 276 | numOpen--; |
| 277 | break; |
| 278 | } |
| 279 | |
| 280 | // Error anytime there is more closing then opening characters |
| 281 | if (numOpen < 0) { |
| 282 | testPrintI("Mismatched number of opening <[ with " |
| 283 | "closing >] in: %s", rectDesc.c_str()); |
| 284 | exit(4); |
| 285 | } |
| 286 | } |
| 287 | |
| 288 | // Description of a rectangle is complete when all opening |
| 289 | // <[ are closed with >] and the string ends with a comma or |
| 290 | // there are no more args. |
| 291 | if ((numOpen == 0) && rectDesc.length() |
| 292 | && ((rectDesc[rectDesc.length() - 1] == ',') |
| 293 | || (optind == argc))) { |
| 294 | // Remove trailing comma if it is present |
| 295 | if (rectDesc[rectDesc.length() - 1] == ',') { |
| 296 | rectDesc.erase(rectDesc.length() - 1); |
| 297 | } |
| 298 | |
| 299 | // Parse string description of rectangle |
| 300 | Rectangle rect = parseRect(rectDesc); |
| 301 | |
| 302 | // Add to the list of rectangles |
| 303 | rectangle.push_back(rect); |
| 304 | |
| 305 | // Prepare for description of another rectangle |
| 306 | rectDesc = string(""); |
| 307 | } |
| 308 | } |
| 309 | |
| 310 | // Create list of frames |
| 311 | hwc_layer_list_t *list; |
| 312 | list = hwcTestCreateLayerList(rectangle.size()); |
| 313 | if (list == NULL) { |
| 314 | testPrintE("hwcTestCreateLayerList failed"); |
| 315 | exit(5); |
| 316 | } |
| 317 | |
| 318 | hwc_layer_t *layer = &list->hwLayers[0]; |
| 319 | for (std::list<Rectangle>::iterator it = rectangle.begin(); |
| 320 | it != rectangle.end(); ++it, ++layer) { |
| 321 | layer->handle = it->texture->handle; |
| 322 | layer->blending = it->blend; |
| 323 | layer->transform = it->transform; |
| 324 | layer->sourceCrop = it->sourceCrop; |
| 325 | layer->displayFrame = it->displayFrame; |
| 326 | |
| 327 | layer->visibleRegionScreen.numRects = 1; |
| 328 | layer->visibleRegionScreen.rects = &layer->displayFrame; |
| 329 | } |
| 330 | |
| 331 | // Perform prepare operation |
| 332 | if (verbose) { testPrintI("Prepare:"); hwcTestDisplayList(list); } |
| 333 | hwcDevice->prepare(hwcDevice, list); |
| 334 | if (verbose) { |
| 335 | testPrintI("Post Prepare:"); |
| 336 | hwcTestDisplayListPrepareModifiable(list); |
| 337 | } |
| 338 | |
| 339 | // Turn off the geometry changed flag |
| 340 | list->flags &= ~HWC_GEOMETRY_CHANGED; |
| 341 | |
| 342 | // Perform the set operation(s) |
| 343 | if (verbose) {testPrintI("Set:"); } |
| 344 | if (verbose) { hwcTestDisplayListHandles(list); } |
| 345 | hwcDevice->set(hwcDevice, dpy, surface, list); |
| 346 | |
| 347 | testDelay(endDelay); |
| 348 | |
| 349 | // Start framework |
| 350 | rv = snprintf(cmd, sizeof(cmd), "%s", CMD_START_FRAMEWORK); |
| 351 | if (rv >= (signed) sizeof(cmd) - 1) { |
| 352 | testPrintE("Command too long for: %s", CMD_START_FRAMEWORK); |
| 353 | exit(6); |
| 354 | } |
| 355 | testExecCmd(cmd); |
| 356 | |
| 357 | return 0; |
| 358 | } |
| 359 | |
| 360 | // Parse string description of rectangle and add it to list of rectangles |
| 361 | // to be rendered. |
| 362 | static Rectangle parseRect(string rectStr) |
| 363 | { |
| 364 | int rv; |
| 365 | string str; |
| 366 | bool error; |
| 367 | istringstream in(rectStr); |
| 368 | const struct hwcTestGraphicFormat *format; |
| 369 | Rectangle rect; |
| 370 | struct hwc_rect hwcRect; |
| 371 | |
| 372 | // Graphic Format |
| 373 | in >> str; |
| 374 | if (!in) { |
| 375 | testPrintE("Error parsing format from: %s", rectStr.c_str()); |
| 376 | exit(20); |
| 377 | } |
| 378 | format = hwcTestGraphicFormatLookup(str.c_str()); |
| 379 | if (format == NULL) { |
| 380 | testPrintE("Unknown graphic format in: %s", rectStr.c_str()); |
| 381 | exit(21); |
| 382 | } |
| 383 | rect.format = format->format; |
| 384 | |
| 385 | // Display Frame |
| 386 | rect.displayFrame = hwcTestParseHwcRect(in, error); |
| 387 | if (error) { |
| 388 | testPrintE("Invalid display frame in: %s", rectStr.c_str()); |
| 389 | exit(22); |
| 390 | } |
| 391 | |
| 392 | // Set default sourceDim and sourceCrop based on size of display frame. |
| 393 | // Default is source size equal to the size of the display frame, with |
| 394 | // the source crop being the entire size of the source frame. |
| 395 | rect.sourceDim = HwcTestDim(rect.displayFrame.right |
| 396 | - rect.displayFrame.left, |
| 397 | rect.displayFrame.bottom |
| 398 | - rect.displayFrame.top); |
| 399 | rect.sourceCrop.left = 0; |
| 400 | rect.sourceCrop.top = 0; |
| 401 | rect.sourceCrop.right = rect.sourceDim.width(); |
| 402 | rect.sourceCrop.bottom = rect.sourceDim.height(); |
| 403 | |
| 404 | // Optional settings |
| 405 | while ((in.tellg() < (streampos) in.str().length()) |
| 406 | && (in.tellg() != (streampos) -1)) { |
| 407 | string attrName; |
| 408 | |
| 409 | in >> attrName; |
| 410 | if (in.eof()) { break; } |
| 411 | if (!in) { |
| 412 | testPrintE("Error reading attribute name in: %s", |
| 413 | rectStr.c_str()); |
| 414 | exit(23); |
| 415 | } |
| 416 | |
| 417 | // Transform |
| 418 | if (attrName == "transform:") { // Transform |
| 419 | string str; |
| 420 | |
| 421 | in >> str; |
| 422 | if (str == "none") { |
| 423 | rect.transform = 0; |
| 424 | } else if (str == "fliph") { |
| 425 | rect.transform = HWC_TRANSFORM_FLIP_H; |
| 426 | } else if (str == "flipv") { |
| 427 | rect.transform = HWC_TRANSFORM_FLIP_V; |
| 428 | } else if (str == "rot90") { |
| 429 | rect.transform = HWC_TRANSFORM_ROT_90; |
| 430 | } else if (str == "rot180") { |
| 431 | rect.transform = HWC_TRANSFORM_ROT_180; |
| 432 | } else if (str == "rot270") { |
| 433 | rect.transform = HWC_TRANSFORM_ROT_270; |
| 434 | } else { |
| 435 | testPrintE("Unknown transform of \"%s\" in: %s", str.c_str(), |
| 436 | rectStr.c_str()); |
| 437 | exit(24); |
| 438 | } |
| 439 | } else if (attrName == "blend:") { // Blend |
| 440 | string str; |
| 441 | |
| 442 | in >> str; |
| 443 | if (str == string("none")) { |
| 444 | rect.blend = HWC_BLENDING_NONE; |
| 445 | } else if (str == "premult") { |
| 446 | rect.blend = HWC_BLENDING_PREMULT; |
| 447 | } else if (str == "coverage") { |
| 448 | rect.blend = HWC_BLENDING_COVERAGE; |
| 449 | } else { |
| 450 | testPrintE("Unknown blend of \"%s\" in: %s", str.c_str(), |
| 451 | rectStr.c_str()); |
| 452 | exit(25); |
| 453 | } |
| 454 | } else if (attrName == "color:") { // Color |
| 455 | rect.color = hwcTestParseColor(in, error); |
| 456 | if (error) { |
| 457 | testPrintE("Error parsing color in: %s", rectStr.c_str()); |
| 458 | exit(26); |
| 459 | } |
| 460 | } else if (attrName == "alpha:") { // Alpha |
| 461 | in >> rect.alpha; |
| 462 | if (!in) { |
| 463 | testPrintE("Error parsing value for alpha attribute in: %s", |
| 464 | rectStr.c_str()); |
| 465 | exit(27); |
| 466 | } |
| 467 | } else if (attrName == "sourceDim:") { // Source Dimension |
| 468 | rect.sourceDim = hwcTestParseDim(in, error); |
| 469 | if (error) { |
| 470 | testPrintE("Error parsing source dimenision in: %s", |
| 471 | rectStr.c_str()); |
| 472 | exit(28); |
| 473 | } |
| 474 | } else if (attrName == "sourceCrop:") { // Source Crop |
| 475 | rect.sourceCrop = hwcTestParseHwcRect(in, error); |
| 476 | if (error) { |
| 477 | testPrintE("Error parsing source crop in: %s", |
| 478 | rectStr.c_str()); |
| 479 | exit(29); |
| 480 | } |
| 481 | } else { // Unknown attribute |
| 482 | testPrintE("Unknown attribute of \"%s\" in: %s", attrName.c_str(), |
| 483 | rectStr.c_str()); |
| 484 | exit(30); |
| 485 | } |
| 486 | } |
| 487 | |
| 488 | // Validate |
| 489 | if (((uint32_t) rect.sourceCrop.left >= rect.sourceDim.width()) |
| 490 | || ((uint32_t) rect.sourceCrop.right > rect.sourceDim.width()) |
| 491 | || ((uint32_t) rect.sourceCrop.top >= rect.sourceDim.height()) |
| 492 | || ((uint32_t) rect.sourceCrop.bottom > rect.sourceDim.height())) { |
| 493 | testPrintE("Invalid source crop in: %s", rectStr.c_str()); |
| 494 | exit(31); |
| 495 | } |
| 496 | if ((rect.displayFrame.left >= width) |
| 497 | || (rect.displayFrame.right > width) |
| 498 | || (rect.displayFrame.top >= height) |
| 499 | || (rect.displayFrame.bottom > height)) { |
| 500 | testPrintE("Invalid display frame in: %s", rectStr.c_str()); |
| 501 | exit(32); |
| 502 | } |
| 503 | if ((rect.alpha < 0.0) || (rect.alpha > 1.0)) { |
| 504 | testPrintE("Invalid alpha in: %s", rectStr.c_str()); |
| 505 | exit(33); |
| 506 | } |
| 507 | |
| 508 | // Create source texture |
| 509 | rect.texture = new GraphicBuffer(rect.sourceDim.width(), |
| 510 | rect.sourceDim.height(), |
| 511 | rect.format, texUsage); |
| 512 | if ((rv = rect.texture->initCheck()) != NO_ERROR) { |
| 513 | testPrintE("source texture initCheck failed, rv: %i", rv); |
| 514 | testPrintE(" %s", rectStr.c_str()); |
| 515 | |
| 516 | } |
| 517 | |
| 518 | // Fill with uniform color |
| 519 | hwcTestFillColor(rect.texture.get(), rect.color, rect.alpha); |
| 520 | if (verbose) { |
| 521 | testPrintI(" buf: %p handle: %p format: %s width: %u height: %u " |
| 522 | "color: %s alpha: %f", |
| 523 | rect.texture.get(), rect.texture->handle, format->desc, |
| 524 | rect.sourceDim.width(), rect.sourceDim.height(), |
| 525 | string(rect.color).c_str(), rect.alpha); |
| 526 | } |
| 527 | |
| 528 | return rect; |
| 529 | } |
| 530 | |
| 531 | void init(void) |
| 532 | { |
| 533 | // Seed pseudo random number generator |
| 534 | // Needed so that the pad areas of frames are filled with a deterministic |
| 535 | // pseudo random value. |
| 536 | srand48(0); |
| 537 | |
| 538 | hwcTestInitDisplay(verbose, &dpy, &surface, &width, &height); |
| 539 | |
| 540 | hwcTestOpenHwc(&hwcDevice); |
| 541 | } |
| 542 | |
| 543 | void printSyntax(const char *cmd) |
| 544 | { |
| 545 | testPrintE(" %s [options] (graphicFormat displayFrame [attributes],)...", |
| 546 | cmd); |
| 547 | testPrintE(" options:"); |
| 548 | testPrintE(" -D End of test delay"); |
| 549 | testPrintE(" -v Verbose"); |
| 550 | testPrintE(""); |
| 551 | testPrintE(" graphic formats:"); |
| 552 | for (unsigned int n1 = 0; n1 < NUMA(hwcTestGraphicFormat); n1++) { |
| 553 | testPrintE(" %s", hwcTestGraphicFormat[n1].desc); |
| 554 | } |
| 555 | testPrintE(""); |
| 556 | testPrintE(" displayFrame"); |
| 557 | testPrintE(" [left, top, right, bottom]"); |
| 558 | testPrintE(""); |
| 559 | testPrintE(" attributes:"); |
| 560 | testPrintE(" transform: none | fliph | flipv | rot90 | rot180 " |
| 561 | " | rot270"); |
| 562 | testPrintE(" blend: none | premult | coverage"); |
| 563 | testPrintE(" color: [0.##, 0.##, 0.##]"); |
| 564 | testPrintE(" alpha: 0.##"); |
| 565 | testPrintE(" sourceDim: [width, height]"); |
| 566 | testPrintE(" sourceCrop: [left, top, right, bottom]"); |
| 567 | testPrintE(""); |
| 568 | testPrintE(" Example:"); |
| 569 | testPrintE(" # White YV12 rectangle, with overlapping turquoise "); |
| 570 | testPrintE(" # RGBA8888 rectangle at 30%% (alpha: 0.7) transparency"); |
| 571 | testPrintE(" %s -v -D 30.0 \\", cmd); |
| 572 | testPrintE(" YV12 [50, 80, 200, 300] transform: none \\"); |
| 573 | testPrintE(" color: [1.0, 0.5, 0.5], \\"); |
| 574 | testPrintE(" RGBA8888 [100, 150, 300, 400] blend: coverage \\"); |
| 575 | testPrintE(" color: [0.251, 0.878, 0.816] alpha: 0.7 \\"); |
| 576 | testPrintE(" sourceDim: [50, 60] sourceCrop: [5, 8, 12, 15]"); |
| 577 | } |