| /* |
| * Copyright (C) 2011 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| */ |
| |
| /* |
| * Hardware Composer Color Equivalence |
| * |
| * Synopsis |
| * hwc_colorequiv [options] eFmt |
| * |
| * options: |
| -v - verbose |
| * -s <0.##, 0.##, 0.##> - Start color (default: <0.0, 0.0, 0.0> |
| * -e <0.##, 0.##, 0.##> - Ending color (default: <1.0, 1.0, 1.0> |
| * -r fmt - reference graphic format |
| * -D #.## - End of test delay |
| * |
| * graphic formats: |
| * RGBA8888 (reference frame default) |
| * RGBX8888 |
| * RGB888 |
| * RGB565 |
| * BGRA8888 |
| * RGBA5551 |
| * RGBA4444 |
| * YV12 |
| * |
| * Description |
| * Renders a horizontal blend in two frames. The first frame is rendered |
| * in the upper third of the display and is called the reference frame. |
| * The second frame is displayed in the middle third and is called the |
| * equivalence frame. The primary purpose of this utility is to verify |
| * that the colors produced in the reference and equivalence frames are |
| * the same. The colors are the same when the colors are the same |
| * vertically between the reference and equivalence frames. |
| * |
| * By default the reference frame is rendered through the use of the |
| * RGBA8888 graphic format. The -r option can be used to specify a |
| * non-default reference frame graphic format. The graphic format of |
| * the equivalence frame is determined by a single required positional |
| * parameter. Intentionally there is no default for the graphic format |
| * of the equivalence frame. |
| * |
| * The horizontal blend in the reference frame is produced from a linear |
| * interpolation from a start color (default: <0.0, 0.0, 0.0> on the left |
| * side to an end color (default <1.0, 1.0, 1.0> on the right side. Where |
| * possible the equivalence frame is rendered with the equivalent color |
| * from the reference frame. A color of black is used in the equivalence |
| * frame for cases where an equivalent color does not exist. |
| */ |
| |
| #define LOG_TAG "hwcColorEquivTest" |
| |
| #include <algorithm> |
| #include <assert.h> |
| #include <cerrno> |
| #include <cmath> |
| #include <cstdlib> |
| #include <ctime> |
| #include <libgen.h> |
| #include <sched.h> |
| #include <sstream> |
| #include <stdint.h> |
| #include <string.h> |
| #include <unistd.h> |
| #include <vector> |
| |
| #include <sys/syscall.h> |
| #include <sys/types.h> |
| #include <sys/wait.h> |
| |
| #include <EGL/egl.h> |
| #include <EGL/eglext.h> |
| #include <GLES2/gl2.h> |
| #include <GLES2/gl2ext.h> |
| |
| #include <ui/GraphicBuffer.h> |
| |
| #include <utils/Log.h> |
| #include <testUtil.h> |
| |
| #include <hardware/hwcomposer.h> |
| |
| #include "hwcTestLib.h" |
| |
| using namespace std; |
| using namespace android; |
| |
| // Defaults for command-line options |
| const bool defaultVerbose = false; |
| const ColorFract defaultStartColor(0.0, 0.0, 0.0); |
| const ColorFract defaultEndColor(1.0, 1.0, 1.0); |
| const char *defaultRefFormat = "RGBA8888"; |
| const float defaultEndDelay = 2.0; // Default delay after rendering graphics |
| |
| // Defines |
| #define MAXSTR 100 |
| #define MAXCMD 200 |
| #define BITSPERBYTE 8 // TODO: Obtain from <values.h>, once |
| // it has been added |
| |
| #define CMD_STOP_FRAMEWORK "stop 2>&1" |
| #define CMD_START_FRAMEWORK "start 2>&1" |
| |
| // Macros |
| #define NUMA(a) (sizeof(a) / sizeof((a)[0])) // Num elements in an array |
| #define MEMCLR(addr, size) do { \ |
| memset((addr), 0, (size)); \ |
| } while (0) |
| |
| // Globals |
| static const int texUsage = GraphicBuffer::USAGE_HW_TEXTURE | |
| GraphicBuffer::USAGE_SW_WRITE_RARELY; |
| static hwc_composer_device_1_t *hwcDevice; |
| static EGLDisplay dpy; |
| static EGLSurface surface; |
| static EGLint width, height; |
| |
| // Functions prototypes |
| void init(void); |
| void printSyntax(const char *cmd); |
| |
| // Command-line option settings |
| static bool verbose = defaultVerbose; |
| static ColorFract startRefColor = defaultStartColor; |
| static ColorFract endRefColor = defaultEndColor; |
| static float endDelay = defaultEndDelay; |
| static const struct hwcTestGraphicFormat *refFormat |
| = hwcTestGraphicFormatLookup(defaultRefFormat); |
| static const struct hwcTestGraphicFormat *equivFormat; |
| |
| /* |
| * Main |
| * |
| * Performs the following high-level sequence of operations: |
| * |
| * 1. Command-line parsing |
| * |
| * 2. Stop framework |
| * |
| * 3. Initialization |
| * |
| * 4. Create Hardware Composer description of reference and equivalence frames |
| * |
| * 5. Have Hardware Composer render the reference and equivalence frames |
| * |
| * 6. Delay for amount of time given by endDelay |
| * |
| * 7. Start framework |
| */ |
| int |
| main(int argc, char *argv[]) |
| { |
| int rv, opt; |
| bool error; |
| char *chptr; |
| char cmd[MAXCMD]; |
| string str; |
| |
| testSetLogCatTag(LOG_TAG); |
| |
| assert(refFormat != NULL); |
| |
| testSetLogCatTag(LOG_TAG); |
| |
| // Parse command line arguments |
| while ((opt = getopt(argc, argv, "vs:e:r:D:?h")) != -1) { |
| switch (opt) { |
| case 'D': // End of test delay |
| // Delay between completion of final pass and restart |
| // of framework |
| endDelay = strtod(optarg, &chptr); |
| if ((*chptr != '\0') || (endDelay < 0.0)) { |
| testPrintE("Invalid command-line specified end of test delay " |
| "of: %s", optarg); |
| exit(1); |
| } |
| break; |
| |
| case 's': // Starting reference color |
| str = optarg; |
| while (optind < argc) { |
| if (*argv[optind] == '-') { break; } |
| char endChar = (str.length() > 1) ? str[str.length() - 1] : 0; |
| if ((endChar == '>') || (endChar == ']')) { break; } |
| str += " " + string(argv[optind++]); |
| } |
| { |
| istringstream in(str); |
| startRefColor = hwcTestParseColor(in, error); |
| // Any parse error or characters not used by parser |
| if (error |
| || (((unsigned int) in.tellg() != in.str().length()) |
| && (in.tellg() != (streampos) -1))) { |
| testPrintE("Invalid command-line specified start " |
| "reference color of: %s", str.c_str()); |
| exit(2); |
| } |
| } |
| break; |
| |
| case 'e': // Ending reference color |
| str = optarg; |
| while (optind < argc) { |
| if (*argv[optind] == '-') { break; } |
| char endChar = (str.length() > 1) ? str[str.length() - 1] : 0; |
| if ((endChar == '>') || (endChar == ']')) { break; } |
| str += " " + string(argv[optind++]); |
| } |
| { |
| istringstream in(str); |
| endRefColor = hwcTestParseColor(in, error); |
| // Any parse error or characters not used by parser |
| if (error |
| || (((unsigned int) in.tellg() != in.str().length()) |
| && (in.tellg() != (streampos) -1))) { |
| testPrintE("Invalid command-line specified end " |
| "reference color of: %s", str.c_str()); |
| exit(3); |
| } |
| } |
| break; |
| |
| case 'r': // Reference graphic format |
| refFormat = hwcTestGraphicFormatLookup(optarg); |
| if (refFormat == NULL) { |
| testPrintE("Unkown command-line specified reference graphic " |
| "format of: %s", optarg); |
| printSyntax(basename(argv[0])); |
| exit(4); |
| } |
| break; |
| |
| case 'v': // Verbose |
| verbose = true; |
| break; |
| |
| case 'h': // Help |
| case '?': |
| default: |
| printSyntax(basename(argv[0])); |
| exit(((optopt == 0) || (optopt == '?')) ? 0 : 5); |
| } |
| } |
| |
| // Expect a single positional parameter, which specifies the |
| // equivalence graphic format. |
| if (argc != (optind + 1)) { |
| testPrintE("Expected a single command-line postional parameter"); |
| printSyntax(basename(argv[0])); |
| exit(6); |
| } |
| equivFormat = hwcTestGraphicFormatLookup(argv[optind]); |
| if (equivFormat == NULL) { |
| testPrintE("Unkown command-line specified equivalence graphic " |
| "format of: %s", argv[optind]); |
| printSyntax(basename(argv[0])); |
| exit(7); |
| } |
| |
| testPrintI("refFormat: %u %s", refFormat->format, refFormat->desc); |
| testPrintI("equivFormat: %u %s", equivFormat->format, equivFormat->desc); |
| testPrintI("startRefColor: %s", ((string) startRefColor).c_str()); |
| testPrintI("endRefColor: %s", ((string) endRefColor).c_str()); |
| testPrintI("endDelay: %f", endDelay); |
| |
| // Stop framework |
| rv = snprintf(cmd, sizeof(cmd), "%s", CMD_STOP_FRAMEWORK); |
| if (rv >= (signed) sizeof(cmd) - 1) { |
| testPrintE("Command too long for: %s", CMD_STOP_FRAMEWORK); |
| exit(8); |
| } |
| testExecCmd(cmd); |
| testDelay(1.0); // TODO - needs means to query whether asynchronous stop |
| // framework operation has completed. For now, just wait |
| // a long time. |
| |
| init(); |
| |
| // Use the upper third of the display for the reference frame and |
| // the middle third for the equivalence frame. |
| unsigned int refHeight = height / 3; |
| unsigned int refPosX = 0; // Reference frame X position |
| unsigned int refWidth = width - refPosX; |
| if ((refWidth & refFormat->wMod) != 0) { |
| refWidth += refFormat->wMod - (refWidth % refFormat->wMod); |
| } |
| unsigned int equivHeight = height / 3; |
| unsigned int equivPosX = 0; // Equivalence frame X position |
| unsigned int equivWidth = width - equivPosX; |
| if ((equivWidth & equivFormat->wMod) != 0) { |
| equivWidth += equivFormat->wMod - (equivWidth % equivFormat->wMod); |
| } |
| |
| // Create reference and equivalence graphic buffers |
| const unsigned int numFrames = 2; |
| sp<GraphicBuffer> refFrame; |
| refFrame = new GraphicBuffer(refWidth, refHeight, |
| refFormat->format, texUsage); |
| if ((rv = refFrame->initCheck()) != NO_ERROR) { |
| testPrintE("refFrame initCheck failed, rv: %i", rv); |
| testPrintE(" width %u height: %u format: %u %s", refWidth, refHeight, |
| refFormat->format, |
| hwcTestGraphicFormat2str(refFormat->format)); |
| exit(9); |
| } |
| testPrintI("refFrame width: %u height: %u format: %u %s", |
| refWidth, refHeight, refFormat->format, |
| hwcTestGraphicFormat2str(refFormat->format)); |
| |
| sp<GraphicBuffer> equivFrame; |
| equivFrame = new GraphicBuffer(equivWidth, equivHeight, |
| equivFormat->format, texUsage); |
| if ((rv = refFrame->initCheck()) != NO_ERROR) { |
| testPrintE("refFrame initCheck failed, rv: %i", rv); |
| testPrintE(" width %u height: %u format: %u %s", refWidth, refHeight, |
| refFormat->format, |
| hwcTestGraphicFormat2str(refFormat->format)); |
| exit(10); |
| } |
| testPrintI("equivFrame width: %u height: %u format: %u %s", |
| equivWidth, equivHeight, equivFormat->format, |
| hwcTestGraphicFormat2str(equivFormat->format)); |
| |
| // Fill the frames with a horizontal blend |
| hwcTestFillColorHBlend(refFrame.get(), refFormat->format, |
| startRefColor, endRefColor); |
| hwcTestFillColorHBlend(equivFrame.get(), refFormat->format, |
| startRefColor, endRefColor); |
| |
| hwc_display_contents_1_t *list; |
| size_t size = sizeof(hwc_display_contents_1_t) + numFrames * sizeof(hwc_layer_1_t); |
| if ((list = (hwc_display_contents_1_t *) calloc(1, size)) == NULL) { |
| testPrintE("Allocate list failed"); |
| exit(11); |
| } |
| list->flags = HWC_GEOMETRY_CHANGED; |
| list->numHwLayers = numFrames; |
| |
| hwc_layer_1_t *layer = &list->hwLayers[0]; |
| layer->handle = refFrame->handle; |
| layer->blending = HWC_BLENDING_NONE; |
| layer->sourceCrop.left = 0; |
| layer->sourceCrop.top = 0; |
| layer->sourceCrop.right = width; |
| layer->sourceCrop.bottom = refHeight; |
| layer->displayFrame.left = 0; |
| layer->displayFrame.top = 0; |
| layer->displayFrame.right = width; |
| layer->displayFrame.bottom = refHeight; |
| layer->visibleRegionScreen.numRects = 1; |
| layer->visibleRegionScreen.rects = &layer->displayFrame; |
| |
| layer++; |
| layer->handle = equivFrame->handle; |
| layer->blending = HWC_BLENDING_NONE; |
| layer->sourceCrop.left = 0; |
| layer->sourceCrop.top = 0; |
| layer->sourceCrop.right = width; |
| layer->sourceCrop.bottom = equivHeight; |
| layer->displayFrame.left = 0; |
| layer->displayFrame.top = refHeight; |
| layer->displayFrame.right = width; |
| layer->displayFrame.bottom = layer->displayFrame.top + equivHeight; |
| layer->visibleRegionScreen.numRects = 1; |
| layer->visibleRegionScreen.rects = &layer->displayFrame; |
| |
| // Perform prepare operation |
| if (verbose) { testPrintI("Prepare:"); hwcTestDisplayList(list); } |
| hwcDevice->prepare(hwcDevice, 1, &list); |
| if (verbose) { |
| testPrintI("Post Prepare:"); |
| hwcTestDisplayListPrepareModifiable(list); |
| } |
| |
| // Turn off the geometry changed flag |
| list->flags &= ~HWC_GEOMETRY_CHANGED; |
| |
| if (verbose) {hwcTestDisplayListHandles(list); } |
| list->dpy = dpy; |
| list->sur = surface; |
| hwcDevice->set(hwcDevice, 1, &list); |
| |
| testDelay(endDelay); |
| |
| // Start framework |
| rv = snprintf(cmd, sizeof(cmd), "%s", CMD_START_FRAMEWORK); |
| if (rv >= (signed) sizeof(cmd) - 1) { |
| testPrintE("Command too long for: %s", CMD_START_FRAMEWORK); |
| exit(12); |
| } |
| testExecCmd(cmd); |
| |
| return 0; |
| } |
| |
| void init(void) |
| { |
| // Seed pseudo random number generator |
| // Seeding causes fill horizontal blend to fill the pad area with |
| // a deterministic set of values. |
| srand48(0); |
| |
| hwcTestInitDisplay(verbose, &dpy, &surface, &width, &height); |
| |
| hwcTestOpenHwc(&hwcDevice); |
| } |
| |
| void printSyntax(const char *cmd) |
| { |
| testPrintE(" %s [options] graphicFormat", cmd); |
| testPrintE(" options:"); |
| testPrintE(" -s <0.##, 0.##, 0.##> - Starting reference color"); |
| testPrintE(" -e <0.##, 0.##, 0.##> - Ending reference color"); |
| testPrintE(" -r format - Reference graphic format"); |
| testPrintE(" -D #.## - End of test delay"); |
| testPrintE(" -v Verbose"); |
| testPrintE(""); |
| testPrintE(" graphic formats:"); |
| for (unsigned int n1 = 0; n1 < NUMA(hwcTestGraphicFormat); n1++) { |
| testPrintE(" %s", hwcTestGraphicFormat[n1].desc); |
| } |
| } |