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