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