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 Color Equivalence 20 * 21 * Synopsis 22 * hwc_colorequiv [options] eFmt 23 * 24 * options: 25 -v - verbose 26 * -s <0.##, 0.##, 0.##> - Start color (default: <0.0, 0.0, 0.0> 27 * -e <0.##, 0.##, 0.##> - Ending color (default: <1.0, 1.0, 1.0> 28 * -r fmt - reference graphic format 29 * -D #.## - End of test delay 30 * 31 * graphic formats: 32 * RGBA8888 (reference frame default) 33 * RGBX8888 34 * RGB888 35 * RGB565 36 * BGRA8888 37 * RGBA5551 38 * RGBA4444 39 * YV12 40 * 41 * Description 42 * Renders a horizontal blend in two frames. The first frame is rendered 43 * in the upper third of the display and is called the reference frame. 44 * The second frame is displayed in the middle third and is called the 45 * equivalence frame. The primary purpose of this utility is to verify 46 * that the colors produced in the reference and equivalence frames are 47 * the same. The colors are the same when the colors are the same 48 * vertically between the reference and equivalence frames. 49 * 50 * By default the reference frame is rendered through the use of the 51 * RGBA8888 graphic format. The -r option can be used to specify a 52 * non-default reference frame graphic format. The graphic format of 53 * the equivalence frame is determined by a single required positional 54 * parameter. Intentionally there is no default for the graphic format 55 * of the equivalence frame. 56 * 57 * The horizontal blend in the reference frame is produced from a linear 58 * interpolation from a start color (default: <0.0, 0.0, 0.0> on the left 59 * side to an end color (default <1.0, 1.0, 1.0> on the right side. Where 60 * possible the equivalence frame is rendered with the equivalent color 61 * from the reference frame. A color of black is used in the equivalence 62 * frame for cases where an equivalent color does not exist. 63 */ 64 65#include <algorithm> 66#include <assert.h> 67#include <cerrno> 68#include <cmath> 69#include <cstdlib> 70#include <ctime> 71#include <libgen.h> 72#include <sched.h> 73#include <sstream> 74#include <stdint.h> 75#include <string.h> 76#include <unistd.h> 77#include <vector> 78 79#include <sys/syscall.h> 80#include <sys/types.h> 81#include <sys/wait.h> 82 83#include <EGL/egl.h> 84#include <EGL/eglext.h> 85#include <GLES2/gl2.h> 86#include <GLES2/gl2ext.h> 87 88#include <ui/GraphicBuffer.h> 89 90#define LOG_TAG "hwcColorEquivTest" 91#include <utils/Log.h> 92#include <testUtil.h> 93 94#include <hardware/hwcomposer.h> 95 96#include "hwcTestLib.h" 97 98using namespace std; 99using namespace android; 100 101// Defaults for command-line options 102const bool defaultVerbose = false; 103const ColorFract defaultStartColor(0.0, 0.0, 0.0); 104const ColorFract defaultEndColor(1.0, 1.0, 1.0); 105const char *defaultRefFormat = "RGBA8888"; 106const float defaultEndDelay = 2.0; // Default delay after rendering graphics 107 108// Defines 109#define MAXSTR 100 110#define MAXCMD 200 111#define BITSPERBYTE 8 // TODO: Obtain from <values.h>, once 112 // it has been added 113 114#define CMD_STOP_FRAMEWORK "stop 2>&1" 115#define CMD_START_FRAMEWORK "start 2>&1" 116 117// Macros 118#define NUMA(a) (sizeof(a) / sizeof(a [0])) // Num elements in an array 119#define MEMCLR(addr, size) do { \ 120 memset((addr), 0, (size)); \ 121 } while (0) 122 123// Globals 124static const int texUsage = GraphicBuffer::USAGE_HW_TEXTURE | 125 GraphicBuffer::USAGE_SW_WRITE_RARELY; 126static hwc_composer_device_1_t *hwcDevice; 127static EGLDisplay dpy; 128static EGLSurface surface; 129static EGLint width, height; 130 131// Functions prototypes 132void init(void); 133void printSyntax(const char *cmd); 134 135// Command-line option settings 136static bool verbose = defaultVerbose; 137static ColorFract startRefColor = defaultStartColor; 138static ColorFract endRefColor = defaultEndColor; 139static float endDelay = defaultEndDelay; 140static const struct hwcTestGraphicFormat *refFormat 141 = hwcTestGraphicFormatLookup(defaultRefFormat); 142static const struct hwcTestGraphicFormat *equivFormat; 143 144/* 145 * Main 146 * 147 * Performs the following high-level sequence of operations: 148 * 149 * 1. Command-line parsing 150 * 151 * 2. Stop framework 152 * 153 * 3. Initialization 154 * 155 * 4. Create Hardware Composer description of reference and equivalence frames 156 * 157 * 5. Have Hardware Composer render the reference and equivalence frames 158 * 159 * 6. Delay for amount of time given by endDelay 160 * 161 * 7. Start framework 162 */ 163int 164main(int argc, char *argv[]) 165{ 166 int rv, opt; 167 bool error; 168 char *chptr; 169 char cmd[MAXCMD]; 170 string str; 171 172 testSetLogCatTag(LOG_TAG); 173 174 assert(refFormat != NULL); 175 176 testSetLogCatTag(LOG_TAG); 177 178 // Parse command line arguments 179 while ((opt = getopt(argc, argv, "vs:e:r:D:?h")) != -1) { 180 switch (opt) { 181 case 'D': // End of test delay 182 // Delay between completion of final pass and restart 183 // of framework 184 endDelay = strtod(optarg, &chptr); 185 if ((*chptr != '\0') || (endDelay < 0.0)) { 186 testPrintE("Invalid command-line specified end of test delay " 187 "of: %s", optarg); 188 exit(1); 189 } 190 break; 191 192 case 's': // Starting reference color 193 str = optarg; 194 while (optind < argc) { 195 if (*argv[optind] == '-') { break; } 196 char endChar = (str.length() > 1) ? str[str.length() - 1] : 0; 197 if ((endChar == '>') || (endChar == ']')) { break; } 198 str += " " + string(argv[optind++]); 199 } 200 { 201 istringstream in(str); 202 startRefColor = hwcTestParseColor(in, error); 203 // Any parse error or characters not used by parser 204 if (error 205 || (((unsigned int) in.tellg() != in.str().length()) 206 && (in.tellg() != (streampos) -1))) { 207 testPrintE("Invalid command-line specified start " 208 "reference color of: %s", str.c_str()); 209 exit(2); 210 } 211 } 212 break; 213 214 case 'e': // Ending reference color 215 str = optarg; 216 while (optind < argc) { 217 if (*argv[optind] == '-') { break; } 218 char endChar = (str.length() > 1) ? str[str.length() - 1] : 0; 219 if ((endChar == '>') || (endChar == ']')) { break; } 220 str += " " + string(argv[optind++]); 221 } 222 { 223 istringstream in(str); 224 endRefColor = hwcTestParseColor(in, error); 225 // Any parse error or characters not used by parser 226 if (error 227 || (((unsigned int) in.tellg() != in.str().length()) 228 && (in.tellg() != (streampos) -1))) { 229 testPrintE("Invalid command-line specified end " 230 "reference color of: %s", str.c_str()); 231 exit(3); 232 } 233 } 234 break; 235 236 case 'r': // Reference graphic format 237 refFormat = hwcTestGraphicFormatLookup(optarg); 238 if (refFormat == NULL) { 239 testPrintE("Unkown command-line specified reference graphic " 240 "format of: %s", optarg); 241 printSyntax(basename(argv[0])); 242 exit(4); 243 } 244 break; 245 246 case 'v': // Verbose 247 verbose = true; 248 break; 249 250 case 'h': // Help 251 case '?': 252 default: 253 printSyntax(basename(argv[0])); 254 exit(((optopt == 0) || (optopt == '?')) ? 0 : 5); 255 } 256 } 257 258 // Expect a single positional parameter, which specifies the 259 // equivalence graphic format. 260 if (argc != (optind + 1)) { 261 testPrintE("Expected a single command-line postional parameter"); 262 printSyntax(basename(argv[0])); 263 exit(6); 264 } 265 equivFormat = hwcTestGraphicFormatLookup(argv[optind]); 266 if (equivFormat == NULL) { 267 testPrintE("Unkown command-line specified equivalence graphic " 268 "format of: %s", argv[optind]); 269 printSyntax(basename(argv[0])); 270 exit(7); 271 } 272 273 testPrintI("refFormat: %u %s", refFormat->format, refFormat->desc); 274 testPrintI("equivFormat: %u %s", equivFormat->format, equivFormat->desc); 275 testPrintI("startRefColor: %s", ((string) startRefColor).c_str()); 276 testPrintI("endRefColor: %s", ((string) endRefColor).c_str()); 277 testPrintI("endDelay: %f", endDelay); 278 279 // Stop framework 280 rv = snprintf(cmd, sizeof(cmd), "%s", CMD_STOP_FRAMEWORK); 281 if (rv >= (signed) sizeof(cmd) - 1) { 282 testPrintE("Command too long for: %s", CMD_STOP_FRAMEWORK); 283 exit(8); 284 } 285 testExecCmd(cmd); 286 testDelay(1.0); // TODO - needs means to query whether asynchronous stop 287 // framework operation has completed. For now, just wait 288 // a long time. 289 290 init(); 291 292 // Use the upper third of the display for the reference frame and 293 // the middle third for the equivalence frame. 294 unsigned int refHeight = height / 3; 295 unsigned int refPosX = 0; // Reference frame X position 296 unsigned int refWidth = width - refPosX; 297 if ((refWidth & refFormat->wMod) != 0) { 298 refWidth += refFormat->wMod - (refWidth % refFormat->wMod); 299 } 300 unsigned int equivHeight = height / 3; 301 unsigned int equivPosX = 0; // Equivalence frame X position 302 unsigned int equivWidth = width - equivPosX; 303 if ((equivWidth & equivFormat->wMod) != 0) { 304 equivWidth += equivFormat->wMod - (equivWidth % equivFormat->wMod); 305 } 306 307 // Create reference and equivalence graphic buffers 308 const unsigned int numFrames = 2; 309 sp<GraphicBuffer> refFrame; 310 refFrame = new GraphicBuffer(refWidth, refHeight, 311 refFormat->format, texUsage); 312 if ((rv = refFrame->initCheck()) != NO_ERROR) { 313 testPrintE("refFrame initCheck failed, rv: %i", rv); 314 testPrintE(" width %u height: %u format: %u %s", refWidth, refHeight, 315 refFormat->format, 316 hwcTestGraphicFormat2str(refFormat->format)); 317 exit(9); 318 } 319 testPrintI("refFrame width: %u height: %u format: %u %s", 320 refWidth, refHeight, refFormat->format, 321 hwcTestGraphicFormat2str(refFormat->format)); 322 323 sp<GraphicBuffer> equivFrame; 324 equivFrame = new GraphicBuffer(equivWidth, equivHeight, 325 equivFormat->format, texUsage); 326 if ((rv = refFrame->initCheck()) != NO_ERROR) { 327 testPrintE("refFrame initCheck failed, rv: %i", rv); 328 testPrintE(" width %u height: %u format: %u %s", refWidth, refHeight, 329 refFormat->format, 330 hwcTestGraphicFormat2str(refFormat->format)); 331 exit(10); 332 } 333 testPrintI("equivFrame width: %u height: %u format: %u %s", 334 equivWidth, equivHeight, equivFormat->format, 335 hwcTestGraphicFormat2str(equivFormat->format)); 336 337 // Fill the frames with a horizontal blend 338 hwcTestFillColorHBlend(refFrame.get(), refFormat->format, 339 startRefColor, endRefColor); 340 hwcTestFillColorHBlend(equivFrame.get(), refFormat->format, 341 startRefColor, endRefColor); 342 343 hwc_display_contents_1_t *list; 344 size_t size = sizeof(hwc_display_contents_1_t) + numFrames * sizeof(hwc_layer_1_t); 345 if ((list = (hwc_display_contents_1_t *) calloc(1, size)) == NULL) { 346 testPrintE("Allocate list failed"); 347 exit(11); 348 } 349 list->flags = HWC_GEOMETRY_CHANGED; 350 list->numHwLayers = numFrames; 351 352 hwc_layer_1_t *layer = &list->hwLayers[0]; 353 layer->handle = refFrame->handle; 354 layer->blending = HWC_BLENDING_NONE; 355 layer->sourceCrop.left = 0; 356 layer->sourceCrop.top = 0; 357 layer->sourceCrop.right = width; 358 layer->sourceCrop.bottom = refHeight; 359 layer->displayFrame.left = 0; 360 layer->displayFrame.top = 0; 361 layer->displayFrame.right = width; 362 layer->displayFrame.bottom = refHeight; 363 layer->visibleRegionScreen.numRects = 1; 364 layer->visibleRegionScreen.rects = &layer->displayFrame; 365 366 layer++; 367 layer->handle = equivFrame->handle; 368 layer->blending = HWC_BLENDING_NONE; 369 layer->sourceCrop.left = 0; 370 layer->sourceCrop.top = 0; 371 layer->sourceCrop.right = width; 372 layer->sourceCrop.bottom = equivHeight; 373 layer->displayFrame.left = 0; 374 layer->displayFrame.top = refHeight; 375 layer->displayFrame.right = width; 376 layer->displayFrame.bottom = layer->displayFrame.top + equivHeight; 377 layer->visibleRegionScreen.numRects = 1; 378 layer->visibleRegionScreen.rects = &layer->displayFrame; 379 380 // Perform prepare operation 381 if (verbose) { testPrintI("Prepare:"); hwcTestDisplayList(list); } 382 hwcDevice->prepare(hwcDevice, 1, &list); 383 if (verbose) { 384 testPrintI("Post Prepare:"); 385 hwcTestDisplayListPrepareModifiable(list); 386 } 387 388 // Turn off the geometry changed flag 389 list->flags &= ~HWC_GEOMETRY_CHANGED; 390 391 if (verbose) {hwcTestDisplayListHandles(list); } 392 list->dpy = dpy; 393 list->sur = surface; 394 hwcDevice->set(hwcDevice, 1, &list); 395 396 testDelay(endDelay); 397 398 // Start framework 399 rv = snprintf(cmd, sizeof(cmd), "%s", CMD_START_FRAMEWORK); 400 if (rv >= (signed) sizeof(cmd) - 1) { 401 testPrintE("Command too long for: %s", CMD_START_FRAMEWORK); 402 exit(12); 403 } 404 testExecCmd(cmd); 405 406 return 0; 407} 408 409void init(void) 410{ 411 // Seed pseudo random number generator 412 // Seeding causes fill horizontal blend to fill the pad area with 413 // a deterministic set of values. 414 srand48(0); 415 416 hwcTestInitDisplay(verbose, &dpy, &surface, &width, &height); 417 418 hwcTestOpenHwc(&hwcDevice); 419} 420 421void printSyntax(const char *cmd) 422{ 423 testPrintE(" %s [options] graphicFormat", cmd); 424 testPrintE(" options:"); 425 testPrintE(" -s <0.##, 0.##, 0.##> - Starting reference color"); 426 testPrintE(" -e <0.##, 0.##, 0.##> - Ending reference color"); 427 testPrintE(" -r format - Reference graphic format"); 428 testPrintE(" -D #.## - End of test delay"); 429 testPrintE(" -v Verbose"); 430 testPrintE(""); 431 testPrintE(" graphic formats:"); 432 for (unsigned int n1 = 0; n1 < NUMA(hwcTestGraphicFormat); n1++) { 433 testPrintE(" %s", hwcTestGraphicFormat[n1].desc); 434 } 435} 436