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
98 using namespace std;
99 using namespace android;
100
101 // Defaults for command-line options
102 const bool defaultVerbose = false;
103 const ColorFract defaultStartColor(0.0, 0.0, 0.0);
104 const ColorFract defaultEndColor(1.0, 1.0, 1.0);
105 const char *defaultRefFormat = "RGBA8888";
106 const 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
124 static const int texUsage = GraphicBuffer::USAGE_HW_TEXTURE |
125 GraphicBuffer::USAGE_SW_WRITE_RARELY;
126 static hwc_composer_device_1_t *hwcDevice;
127 static EGLDisplay dpy;
128 static EGLSurface surface;
129 static EGLint width, height;
130
131 // Functions prototypes
132 void init(void);
133 void printSyntax(const char *cmd);
134
135 // Command-line option settings
136 static bool verbose = defaultVerbose;
137 static ColorFract startRefColor = defaultStartColor;
138 static ColorFract endRefColor = defaultEndColor;
139 static float endDelay = defaultEndDelay;
140 static const struct hwcTestGraphicFormat *refFormat
141 = hwcTestGraphicFormatLookup(defaultRefFormat);
142 static 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 */
163 int
main(int argc,char * argv[])164 main(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
init(void)409 void 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
printSyntax(const char * cmd)421 void 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