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