diff options
author | Louis Huemiller <lhuemill@google.com> | 2011-01-05 18:53:47 -0800 |
---|---|---|
committer | Louis Huemiller <lhuemill@google.com> | 2011-01-06 21:25:50 -0800 |
commit | ec0da1a5ffc0c856efea16e6a05f2ce9e7c82a94 (patch) | |
tree | e02c8a7573f0655252bab8dc2c4d4ca074e89ab5 /opengl | |
parent | 325a0f969c1d803d7e39a9caee8cc3d400350659 (diff) | |
download | frameworks_base-ec0da1a5ffc0c856efea16e6a05f2ce9e7c82a94.zip frameworks_base-ec0da1a5ffc0c856efea16e6a05f2ce9e7c82a94.tar.gz frameworks_base-ec0da1a5ffc0c856efea16e6a05f2ce9e7c82a94.tar.bz2 |
Hardware Composer new and refactored test cases
Change-Id: Iabf46fc5d75891f917e06a257470a0e3f2bd3c95
Diffstat (limited to 'opengl')
-rw-r--r-- | opengl/tests/hwc/Android.mk | 103 | ||||
-rw-r--r-- | opengl/tests/hwc/hwcColorEquiv.cpp | 436 | ||||
-rw-r--r-- | opengl/tests/hwc/hwcRects.cpp | 575 | ||||
-rw-r--r-- | opengl/tests/hwc/hwcStress.cpp (renamed from opengl/tests/hwc/hwc_stress.cpp) | 677 | ||||
-rw-r--r-- | opengl/tests/hwc/hwcTestLib.cpp | 995 | ||||
-rw-r--r-- | opengl/tests/hwc/hwcTestLib.h | 133 | ||||
-rw-r--r-- | opengl/tests/include/glTestLib.h | 34 | ||||
-rw-r--r-- | opengl/tests/lib/Android.mk | 32 | ||||
-rw-r--r-- | opengl/tests/lib/glTestLib.cpp | 119 |
9 files changed, 2455 insertions, 649 deletions
diff --git a/opengl/tests/hwc/Android.mk b/opengl/tests/hwc/Android.mk index 743dbf1..93a5545 100644 --- a/opengl/tests/hwc/Android.mk +++ b/opengl/tests/hwc/Android.mk @@ -1,7 +1,40 @@ +# Copyright (C) 2010 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. + LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) -LOCAL_SRC_FILES:= hwc_stress.cpp +LOCAL_MODULE_TAGS := tests +LOCAL_MODULE:= libhwcTest +LOCAL_SRC_FILES:= hwcTestLib.cpp +LOCAL_C_INCLUDES += system/extras/tests/include \ + bionic \ + bionic/libstdc++/include \ + external/stlport/stlport \ + frameworks/base/opengl/tests \ + frameworks/base/opengl/tests/include \ + +LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES + +LOCAL_SHARED_LIBRARIES += libcutils libutils libstlport +LOCAL_STATIC_LIBRARIES += libglTest +LOCAL_PRELINK_MODULE := false + +include $(BUILD_STATIC_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_SRC_FILES:= hwcStress.cpp LOCAL_SHARED_LIBRARIES := \ libcutils \ @@ -12,12 +45,18 @@ LOCAL_SHARED_LIBRARIES := \ LOCAL_STATIC_LIBRARIES := \ libtestUtil \ + libglTest \ + libhwcTest \ LOCAL_C_INCLUDES += \ system/extras/tests/include \ hardware/libhardware/include \ + frameworks/base/opengl/tests \ + frameworks/base/opengl/tests/include \ + +LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES -LOCAL_MODULE:= hwc_stress +LOCAL_MODULE:= hwcStress LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)/nativestresstest LOCAL_MODULE_TAGS := tests @@ -25,3 +64,63 @@ LOCAL_MODULE_TAGS := tests LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES include $(BUILD_NATIVE_TEST) + +include $(CLEAR_VARS) +LOCAL_SRC_FILES:= hwcRects.cpp + +LOCAL_SHARED_LIBRARIES := \ + libcutils \ + libEGL \ + libGLESv2 \ + libui \ + libhardware \ + +LOCAL_STATIC_LIBRARIES := \ + libtestUtil \ + libglTest \ + libhwcTest \ + +LOCAL_C_INCLUDES += \ + system/extras/tests/include \ + hardware/libhardware/include \ + frameworks/base/opengl/tests \ + frameworks/base/opengl/tests/include \ + +LOCAL_MODULE:= hwcRects +LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)/nativeutil + +LOCAL_MODULE_TAGS := tests + +LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES + +include $(BUILD_NATIVE_TEST) + +include $(CLEAR_VARS) +LOCAL_SRC_FILES:= hwcColorEquiv.cpp + +LOCAL_SHARED_LIBRARIES := \ + libcutils \ + libEGL \ + libGLESv2 \ + libui \ + libhardware \ + +LOCAL_STATIC_LIBRARIES := \ + libtestUtil \ + libglTest \ + libhwcTest \ + +LOCAL_C_INCLUDES += \ + system/extras/tests/include \ + hardware/libhardware/include \ + frameworks/base/opengl/tests \ + frameworks/base/opengl/tests/include \ + +LOCAL_MODULE:= hwcColorEquiv +LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)/nativeutil + +LOCAL_MODULE_TAGS := tests + +LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES + +include $(BUILD_NATIVE_TEST) diff --git a/opengl/tests/hwc/hwcColorEquiv.cpp b/opengl/tests/hwc/hwcColorEquiv.cpp new file mode 100644 index 0000000..4a87a05 --- /dev/null +++ b/opengl/tests/hwc/hwcColorEquiv.cpp @@ -0,0 +1,436 @@ +/* + * 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. + */ + +#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/FramebufferNativeWindow.h> +#include <ui/GraphicBuffer.h> +#include <ui/EGLUtils.h> + +#define LOG_TAG "hwcColorEquivTest" +#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_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; + unsigned int pass; + char cmd[MAXCMD]; + string str; + + testSetLogCatTag(LOG_TAG); + + assert(refFormat != NULL); + + // 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 refPosY = 0; // Reference frame Y position + 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 equivPosY = refHeight; // Equivalence frame Y position + 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_layer_list_t *list; + size_t size = sizeof(hwc_layer_list) + numFrames * sizeof(hwc_layer_t); + if ((list = (hwc_layer_list_t *) calloc(1, size)) == NULL) { + testPrintE("Allocate list failed"); + exit(11); + } + list->flags = HWC_GEOMETRY_CHANGED; + list->numHwLayers = numFrames; + + hwc_layer_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, list); + if (verbose) { + testPrintI("Post Prepare:"); + hwcTestDisplayListPrepareModifiable(list); + } + + // Turn off the geometry changed flag + list->flags &= ~HWC_GEOMETRY_CHANGED; + + if (verbose) {hwcTestDisplayListHandles(list); } + hwcDevice->set(hwcDevice, dpy, surface, 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); + } +} diff --git a/opengl/tests/hwc/hwcRects.cpp b/opengl/tests/hwc/hwcRects.cpp new file mode 100644 index 0000000..c93124e --- /dev/null +++ b/opengl/tests/hwc/hwcRects.cpp @@ -0,0 +1,575 @@ +/* + * 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 Rectangles + * + * Synopsis + * hwcRects [options] (graphicFormat displayFrame [attributes],)... + * options: + * -D #.## - End of test delay + * -v Verbose"); + * + * graphic formats: + * RGBA8888 (reference frame default) + * RGBX8888 + * RGB888 + * RGB565 + * BGRA8888 + * RGBA5551 + * RGBA4444 + * YV12 + * + * displayFrame + * [left, top, right, bottom] + * + * attributes: + * transform: none | fliph | flipv | rot90 | rot180 | rot270 + * blend: none | premult | coverage + * color: [0.##, 0.##, 0.##] + * alpha: 0.## + * sourceDim: [width, height] + * sourceCrop: [left, top, right, bottom] + * + * Example: + * # White YV12 rectangle, with overlapping turquoise + * # RGBA8888 rectangle at 30%% (alpha: 0.7) transparency + * hwcRects -v -D 30.0 \ + * YV12 [50, 80, 200, 300] transform: none \ + * color: [1.0, 0.5, 0.5], \ + * RGBA8888 [100, 150, 300, 400] blend: coverage \ + * color: [0.251, 0.878, 0.816] alpha: 0.7 \ + * sourceDim: [50, 60] sourceCrop: [5, 8, 12, 15] + * + * Description + * Constructs a Hardware Composer (HWC) list of frames from + * command-line specified parameters. Then sends it to the HWC + * be rendered. The intended purpose of this tool is as a means to + * reproduce and succinctly specify an observed HWC operation, with + * no need to modify/compile a program. + * + * The command-line syntax consists of a few standard command-line + * options and then a description of one or more frames. The frame + * descriptions are separated from one another via a comma. The + * beginning of a frame description requires the specification + * of the graphic format and then the display frame rectangle where + * the frame will be displayed. The display frame rectangle is + * specified as follows, with the right and bottom coordinates being + * exclusive values: + * + * [left, top, right, bottom] + * + * After these two required parameters each frame description can + * specify 1 or more optional attributes. The name of each optional + * attribute is preceded by a colon. The current implementation + * then requires white space after the colon and then the value of + * the attribute is specified. See the synopsis section above for + * a list of attributes and the format of their expected value. + */ + +#include <algorithm> +#include <assert.h> +#include <cerrno> +#include <cmath> +#include <cstdlib> +#include <ctime> +#include <istream> +#include <libgen.h> +#include <list> +#include <sched.h> +#include <sstream> +#include <stdint.h> +#include <string.h> +#include <unistd.h> + +#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/FramebufferNativeWindow.h> +#include <ui/GraphicBuffer.h> +#include <ui/EGLUtils.h> + +#define LOG_TAG "hwcColorEquivTest" +#include <utils/Log.h> +#include <testUtil.h> + +#include <hardware/hwcomposer.h> + +#include <glTestLib.h> +#include <hwc/hwcTestLib.h> + +using namespace std; +using namespace android; + +// Defaults +const bool defaultVerbose = false; +const float defaultEndDelay = 2.0; // Default delay after rendering graphics + +const uint32_t defaultFormat = HAL_PIXEL_FORMAT_RGBA_8888; +const int32_t defaultTransform = 0; +const uint32_t defaultBlend = HWC_BLENDING_NONE; +const ColorFract defaultColor(0.5, 0.5, 0.5); +const float defaultAlpha = 1.0; // Opaque +const HwcTestDim defaultSourceDim(1, 1); +const struct hwc_rect defaultSourceCrop = {0, 0, 1, 1}; +const struct hwc_rect defaultDisplayFrame = {0, 0, 100, 100}; + +// Defines +#define MAXCMD 200 +#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 + +// Local types +class Rectangle { +public: + Rectangle() : format(defaultFormat), transform(defaultTransform), + blend(defaultBlend), color(defaultColor), + alpha(defaultAlpha), sourceDim(defaultSourceDim), + sourceCrop(defaultSourceCrop), + displayFrame(defaultDisplayFrame) {}; + + uint32_t format; + uint32_t transform; + int32_t blend; + ColorFract color; + float alpha; + HwcTestDim sourceDim; + struct hwc_rect sourceCrop; + struct hwc_rect displayFrame; + + sp<GraphicBuffer> texture; +}; + +// Globals +list<Rectangle> rectangle; +static const int texUsage = GraphicBuffer::USAGE_HW_TEXTURE | + GraphicBuffer::USAGE_SW_WRITE_RARELY; +static hwc_composer_device_t *hwcDevice; +static EGLDisplay dpy; +static EGLSurface surface; +static EGLint width, height; + +// Function prototypes +static Rectangle parseRect(string rectStr); +void init(void); +void printSyntax(const char *cmd); + +// Command-line option settings +static bool verbose = defaultVerbose; +static float endDelay = defaultEndDelay; + +/* + * Main + * + * Performs the following high-level sequence of operations: + * + * 1. Parse command-line options + * + * 2. Stop framework + * + * 3. Initialization + * + * 4. Parse frame descriptions + * + * 5. Create HWC list from frame descriptions + * + * 6. Have HWC render the list description of the frames + * + * 7. Delay for amount of time given by endDelay + * + * 8. Start framework + */ +int +main(int argc, char *argv[]) +{ + int rv, opt; + char *chptr; + bool error; + string str; + char cmd[MAXCMD]; + + // Parse command line arguments + while ((opt = getopt(argc, argv, "D:v?h")) != -1) { + switch (opt) { + case 'D': // End of test delay + 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 'v': // Verbose + verbose = true; + break; + + case 'h': // Help + case '?': + default: + printSyntax(basename(argv[0])); + exit(((optopt == 0) || (optopt == '?')) ? 0 : 2); + } + } + + // 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(3); + } + testExecCmd(cmd); + testDelay(1.0); // TODO - needs means to query whether asyncronous stop + // framework operation has completed. For now, just wait + // a long time. + + init(); + + // Parse rectangle descriptions + int numOpen = 0; // Current number of unmatched <[ + string rectDesc(""); // String description of a single rectangle + while (optind < argc) { + string argNext = string(argv[optind++]); + + if (rectDesc.length()) { rectDesc += ' '; } + rectDesc += argNext; + + // Count number of opening <[ and matching >] + // At this point not worried about an opening character being + // matched by it's corresponding closing character. For example, + // "<1.0, 2.0]" is incorrect because the opening < should be matched + // with a closing >, instead of the closing ]. Such errors are + // detected when the actual value is parsed. + for (unsigned int n1 = 0; n1 < argNext.length(); n1++) { + switch(argNext[n1]) { + case '[': + case '<': + numOpen++; + break; + + case ']': + case '>': + numOpen--; + break; + } + + // Error anytime there is more closing then opening characters + if (numOpen < 0) { + testPrintI("Mismatched number of opening <[ with " + "closing >] in: %s", rectDesc.c_str()); + exit(4); + } + } + + // Description of a rectangle is complete when all opening + // <[ are closed with >] and the string ends with a comma or + // there are no more args. + if ((numOpen == 0) && rectDesc.length() + && ((rectDesc[rectDesc.length() - 1] == ',') + || (optind == argc))) { + // Remove trailing comma if it is present + if (rectDesc[rectDesc.length() - 1] == ',') { + rectDesc.erase(rectDesc.length() - 1); + } + + // Parse string description of rectangle + Rectangle rect = parseRect(rectDesc); + + // Add to the list of rectangles + rectangle.push_back(rect); + + // Prepare for description of another rectangle + rectDesc = string(""); + } + } + + // Create list of frames + hwc_layer_list_t *list; + list = hwcTestCreateLayerList(rectangle.size()); + if (list == NULL) { + testPrintE("hwcTestCreateLayerList failed"); + exit(5); + } + + hwc_layer_t *layer = &list->hwLayers[0]; + for (std::list<Rectangle>::iterator it = rectangle.begin(); + it != rectangle.end(); ++it, ++layer) { + layer->handle = it->texture->handle; + layer->blending = it->blend; + layer->transform = it->transform; + layer->sourceCrop = it->sourceCrop; + layer->displayFrame = it->displayFrame; + + layer->visibleRegionScreen.numRects = 1; + layer->visibleRegionScreen.rects = &layer->displayFrame; + } + + // Perform prepare operation + if (verbose) { testPrintI("Prepare:"); hwcTestDisplayList(list); } + hwcDevice->prepare(hwcDevice, list); + if (verbose) { + testPrintI("Post Prepare:"); + hwcTestDisplayListPrepareModifiable(list); + } + + // Turn off the geometry changed flag + list->flags &= ~HWC_GEOMETRY_CHANGED; + + // Perform the set operation(s) + if (verbose) {testPrintI("Set:"); } + if (verbose) { hwcTestDisplayListHandles(list); } + hwcDevice->set(hwcDevice, dpy, surface, 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(6); + } + testExecCmd(cmd); + + return 0; +} + +// Parse string description of rectangle and add it to list of rectangles +// to be rendered. +static Rectangle parseRect(string rectStr) +{ + int rv; + string str; + bool error; + istringstream in(rectStr); + const struct hwcTestGraphicFormat *format; + Rectangle rect; + struct hwc_rect hwcRect; + + // Graphic Format + in >> str; + if (!in) { + testPrintE("Error parsing format from: %s", rectStr.c_str()); + exit(20); + } + format = hwcTestGraphicFormatLookup(str.c_str()); + if (format == NULL) { + testPrintE("Unknown graphic format in: %s", rectStr.c_str()); + exit(21); + } + rect.format = format->format; + + // Display Frame + rect.displayFrame = hwcTestParseHwcRect(in, error); + if (error) { + testPrintE("Invalid display frame in: %s", rectStr.c_str()); + exit(22); + } + + // Set default sourceDim and sourceCrop based on size of display frame. + // Default is source size equal to the size of the display frame, with + // the source crop being the entire size of the source frame. + rect.sourceDim = HwcTestDim(rect.displayFrame.right + - rect.displayFrame.left, + rect.displayFrame.bottom + - rect.displayFrame.top); + rect.sourceCrop.left = 0; + rect.sourceCrop.top = 0; + rect.sourceCrop.right = rect.sourceDim.width(); + rect.sourceCrop.bottom = rect.sourceDim.height(); + + // Optional settings + while ((in.tellg() < (streampos) in.str().length()) + && (in.tellg() != (streampos) -1)) { + string attrName; + + in >> attrName; + if (in.eof()) { break; } + if (!in) { + testPrintE("Error reading attribute name in: %s", + rectStr.c_str()); + exit(23); + } + + // Transform + if (attrName == "transform:") { // Transform + string str; + + in >> str; + if (str == "none") { + rect.transform = 0; + } else if (str == "fliph") { + rect.transform = HWC_TRANSFORM_FLIP_H; + } else if (str == "flipv") { + rect.transform = HWC_TRANSFORM_FLIP_V; + } else if (str == "rot90") { + rect.transform = HWC_TRANSFORM_ROT_90; + } else if (str == "rot180") { + rect.transform = HWC_TRANSFORM_ROT_180; + } else if (str == "rot270") { + rect.transform = HWC_TRANSFORM_ROT_270; + } else { + testPrintE("Unknown transform of \"%s\" in: %s", str.c_str(), + rectStr.c_str()); + exit(24); + } + } else if (attrName == "blend:") { // Blend + string str; + + in >> str; + if (str == string("none")) { + rect.blend = HWC_BLENDING_NONE; + } else if (str == "premult") { + rect.blend = HWC_BLENDING_PREMULT; + } else if (str == "coverage") { + rect.blend = HWC_BLENDING_COVERAGE; + } else { + testPrintE("Unknown blend of \"%s\" in: %s", str.c_str(), + rectStr.c_str()); + exit(25); + } + } else if (attrName == "color:") { // Color + rect.color = hwcTestParseColor(in, error); + if (error) { + testPrintE("Error parsing color in: %s", rectStr.c_str()); + exit(26); + } + } else if (attrName == "alpha:") { // Alpha + in >> rect.alpha; + if (!in) { + testPrintE("Error parsing value for alpha attribute in: %s", + rectStr.c_str()); + exit(27); + } + } else if (attrName == "sourceDim:") { // Source Dimension + rect.sourceDim = hwcTestParseDim(in, error); + if (error) { + testPrintE("Error parsing source dimenision in: %s", + rectStr.c_str()); + exit(28); + } + } else if (attrName == "sourceCrop:") { // Source Crop + rect.sourceCrop = hwcTestParseHwcRect(in, error); + if (error) { + testPrintE("Error parsing source crop in: %s", + rectStr.c_str()); + exit(29); + } + } else { // Unknown attribute + testPrintE("Unknown attribute of \"%s\" in: %s", attrName.c_str(), + rectStr.c_str()); + exit(30); + } + } + + // Validate + if (((uint32_t) rect.sourceCrop.left >= rect.sourceDim.width()) + || ((uint32_t) rect.sourceCrop.right > rect.sourceDim.width()) + || ((uint32_t) rect.sourceCrop.top >= rect.sourceDim.height()) + || ((uint32_t) rect.sourceCrop.bottom > rect.sourceDim.height())) { + testPrintE("Invalid source crop in: %s", rectStr.c_str()); + exit(31); + } + if ((rect.displayFrame.left >= width) + || (rect.displayFrame.right > width) + || (rect.displayFrame.top >= height) + || (rect.displayFrame.bottom > height)) { + testPrintE("Invalid display frame in: %s", rectStr.c_str()); + exit(32); + } + if ((rect.alpha < 0.0) || (rect.alpha > 1.0)) { + testPrintE("Invalid alpha in: %s", rectStr.c_str()); + exit(33); + } + + // Create source texture + rect.texture = new GraphicBuffer(rect.sourceDim.width(), + rect.sourceDim.height(), + rect.format, texUsage); + if ((rv = rect.texture->initCheck()) != NO_ERROR) { + testPrintE("source texture initCheck failed, rv: %i", rv); + testPrintE(" %s", rectStr.c_str()); + + } + + // Fill with uniform color + hwcTestFillColor(rect.texture.get(), rect.color, rect.alpha); + if (verbose) { + testPrintI(" buf: %p handle: %p format: %s width: %u height: %u " + "color: %s alpha: %f", + rect.texture.get(), rect.texture->handle, format->desc, + rect.sourceDim.width(), rect.sourceDim.height(), + string(rect.color).c_str(), rect.alpha); + } + + return rect; +} + +void init(void) +{ + // Seed pseudo random number generator + // Needed so that the pad areas of frames are filled with a deterministic + // pseudo random value. + srand48(0); + + hwcTestInitDisplay(verbose, &dpy, &surface, &width, &height); + + hwcTestOpenHwc(&hwcDevice); +} + +void printSyntax(const char *cmd) +{ + testPrintE(" %s [options] (graphicFormat displayFrame [attributes],)...", + cmd); + testPrintE(" options:"); + 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); + } + testPrintE(""); + testPrintE(" displayFrame"); + testPrintE(" [left, top, right, bottom]"); + testPrintE(""); + testPrintE(" attributes:"); + testPrintE(" transform: none | fliph | flipv | rot90 | rot180 " + " | rot270"); + testPrintE(" blend: none | premult | coverage"); + testPrintE(" color: [0.##, 0.##, 0.##]"); + testPrintE(" alpha: 0.##"); + testPrintE(" sourceDim: [width, height]"); + testPrintE(" sourceCrop: [left, top, right, bottom]"); + testPrintE(""); + testPrintE(" Example:"); + testPrintE(" # White YV12 rectangle, with overlapping turquoise "); + testPrintE(" # RGBA8888 rectangle at 30%% (alpha: 0.7) transparency"); + testPrintE(" %s -v -D 30.0 \\", cmd); + testPrintE(" YV12 [50, 80, 200, 300] transform: none \\"); + testPrintE(" color: [1.0, 0.5, 0.5], \\"); + testPrintE(" RGBA8888 [100, 150, 300, 400] blend: coverage \\"); + testPrintE(" color: [0.251, 0.878, 0.816] alpha: 0.7 \\"); + testPrintE(" sourceDim: [50, 60] sourceCrop: [5, 8, 12, 15]"); +} diff --git a/opengl/tests/hwc/hwc_stress.cpp b/opengl/tests/hwc/hwcStress.cpp index 580eb83..1cefb4b 100644 --- a/opengl/tests/hwc/hwc_stress.cpp +++ b/opengl/tests/hwc/hwcStress.cpp @@ -92,8 +92,6 @@ #include <unistd.h> #include <vector> -#include <arpa/inet.h> // For ntohl() and htonl() - #include <sys/syscall.h> #include <sys/types.h> #include <sys/wait.h> @@ -113,6 +111,9 @@ #include <hardware/hwcomposer.h> +#include <glTestLib.h> +#include <hwc/hwcTestLib.h> + using namespace std; using namespace android; @@ -167,55 +168,7 @@ bool eFlag, sFlag, pFlag; memset((addr), 0, (size)); \ } while (0) -// Represent RGB color as fraction of color components. -// Each of the color components are expected in the range [0.0, 1.0] -class RGBColor { - public: - RGBColor(): _r(0.0), _g(0.0), _b(0.0) {}; - RGBColor(float f): _r(f), _g(f), _b(f) {}; // Gray - RGBColor(float r, float g, float b): _r(r), _g(g), _b(b) {}; - float r(void) const { return _r; } - float g(void) const { return _g; } - float b(void) const { return _b; } - - private: - float _r; - float _g; - float _b; -}; - -// Represent YUV color as fraction of color components. -// Each of the color components are expected in the range [0.0, 1.0] -class YUVColor { - public: - YUVColor(): _y(0.0), _u(0.0), _v(0.0) {}; - YUVColor(float f): _y(f), _u(0.0), _v(0.0) {}; // Gray - YUVColor(float y, float u, float v): _y(y), _u(u), _v(v) {}; - float y(void) const { return _y; } - float u(void) const { return _u; } - float v(void) const { return _v; } - - private: - float _y; - float _u; - float _v; -}; - // File scope constants -static const struct graphicFormat { - unsigned int format; - const char *desc; - unsigned int wMod, hMod; // Width/height mod this value must equal zero -} graphicFormat[] = { - {HAL_PIXEL_FORMAT_RGBA_8888, "RGBA8888", 1, 1}, - {HAL_PIXEL_FORMAT_RGBX_8888, "RGBX8888", 1, 1}, - {HAL_PIXEL_FORMAT_RGB_888, "RGB888", 1, 1}, - {HAL_PIXEL_FORMAT_RGB_565, "RGB565", 1, 1}, - {HAL_PIXEL_FORMAT_BGRA_8888, "BGRA8888", 1, 1}, - {HAL_PIXEL_FORMAT_RGBA_5551, "RGBA5551", 1, 1}, - {HAL_PIXEL_FORMAT_RGBA_4444, "RGBA4444", 1, 1}, - {HAL_PIXEL_FORMAT_YV12, "YV12", 2, 2}, -}; const unsigned int blendingOps[] = { HWC_BLENDING_NONE, HWC_BLENDING_PREMULT, @@ -240,30 +193,15 @@ const vector<unsigned int> vecTransformFlags(transformFlags, // File scope globals static const int texUsage = GraphicBuffer::USAGE_HW_TEXTURE | GraphicBuffer::USAGE_SW_WRITE_RARELY; -static hw_module_t const *hwcModule; static hwc_composer_device_t *hwcDevice; -static vector <vector <sp<GraphicBuffer> > > frames; static EGLDisplay dpy; -static EGLContext context; static EGLSurface surface; static EGLint width, height; +static vector <vector <sp<GraphicBuffer> > > frames; // File scope prototypes -static void execCmd(const char *cmd); -static void checkEglError(const char* op, EGLBoolean returnVal = EGL_TRUE); -static void checkGlError(const char* op); -static void printEGLConfiguration(EGLDisplay dpy, EGLConfig config); -static void printGLString(const char *name, GLenum s); -static hwc_layer_list_t *createLayerList(size_t numLayers); -static void freeLayerList(hwc_layer_list_t *list); -static void fillColor(GraphicBuffer *gBuf, RGBColor color, float trans); -static void fillColor(GraphicBuffer *gBuf, YUVColor color, float trans); void init(void); void initFrames(unsigned int seed); -void displayList(hwc_layer_list_t *list); -void displayListPrepareModifiable(hwc_layer_list_t *list); -void displayListHandles(hwc_layer_list_t *list); -const char *graphicFormat2str(unsigned int format); template <class T> vector<T> vectorRandSelect(const vector<T>& vec, size_t num); template <class T> T vectorOr(const vector<T>& vec); @@ -441,8 +379,8 @@ main(int argc, char *argv[]) testPrintE("Command too long for: %s", CMD_STOP_FRAMEWORK); exit(14); } - execCmd(cmd); - testDelay(1.0); // TODO - needs means to query whether asyncronous stop + testExecCmd(cmd); + testDelay(1.0); // TODO - need means to query whether asyncronous stop // framework operation has completed. For now, just wait // a long time. @@ -473,9 +411,9 @@ main(int argc, char *argv[]) srand48(pass); hwc_layer_list_t *list; - list = createLayerList(testRandMod(frames.size()) + 1); + list = hwcTestCreateLayerList(testRandMod(frames.size()) + 1); if (list == NULL) { - testPrintE("createLayerList failed"); + testPrintE("hwcTestCreateLayerList failed"); exit(20); } @@ -540,11 +478,11 @@ main(int argc, char *argv[]) } // Perform prepare operation - if (verbose) { testPrintI("Prepare:"); displayList(list); } + if (verbose) { testPrintI("Prepare:"); hwcTestDisplayList(list); } hwcDevice->prepare(hwcDevice, list); if (verbose) { testPrintI("Post Prepare:"); - displayListPrepareModifiable(list); + hwcTestDisplayListPrepareModifiable(list); } // Turn off the geometry changed flag @@ -553,7 +491,7 @@ main(int argc, char *argv[]) // Perform the set operation(s) if (verbose) {testPrintI("Set:"); } for (unsigned int n1 = 0; n1 < numSet; n1++) { - if (verbose) {displayListHandles(list); } + if (verbose) { hwcTestDisplayListHandles(list); } hwcDevice->set(hwcDevice, dpy, surface, list); // Prandomly select a new set of handles @@ -567,8 +505,7 @@ main(int argc, char *argv[]) testDelay(perSetDelay); } - - freeLayerList(list); + hwcTestFreeLayerList(list); testPrintI("==== Completed pass: %u", pass); } @@ -580,448 +517,24 @@ main(int argc, char *argv[]) testPrintE("Command too long for: %s", CMD_START_FRAMEWORK); exit(21); } - execCmd(cmd); + testExecCmd(cmd); testPrintI("Successfully completed %u passes", pass - startPass); return 0; } -/* - * Execute Command - * - * Executes the command pointed to by cmd. Output from the - * executed command is captured and sent to LogCat Info. Once - * the command has finished execution, it's exit status is captured - * and checked for an exit status of zero. Any other exit status - * causes diagnostic information to be printed and an immediate - * testcase failure. - */ -static void execCmd(const char *cmd) -{ - FILE *fp; - int rv; - int status; - char str[MAXSTR]; - - // Display command to be executed - testPrintI("cmd: %s", cmd); - - // Execute the command - fflush(stdout); - if ((fp = popen(cmd, "r")) == NULL) { - testPrintE("execCmd popen failed, errno: %i", errno); - exit(30); - } - - // Obtain and display each line of output from the executed command - while (fgets(str, sizeof(str), fp) != NULL) { - if ((strlen(str) > 1) && (str[strlen(str) - 1] == '\n')) { - str[strlen(str) - 1] = '\0'; - } - testPrintI(" out: %s", str); - } - - // Obtain and check return status of executed command. - // Fail on non-zero exit status - status = pclose(fp); - if (!(WIFEXITED(status) && (WEXITSTATUS(status) == 0))) { - testPrintE("Unexpected command failure"); - testPrintE(" status: %#x", status); - if (WIFEXITED(status)) { - testPrintE("WEXITSTATUS: %i", WEXITSTATUS(status)); - } - if (WIFSIGNALED(status)) { - testPrintE("WTERMSIG: %i", WTERMSIG(status)); - } - exit(31); - } -} - -static void checkEglError(const char* op, EGLBoolean returnVal) { - if (returnVal != EGL_TRUE) { - testPrintE("%s() returned %d", op, returnVal); - } - - for (EGLint error = eglGetError(); error != EGL_SUCCESS; error - = eglGetError()) { - testPrintE("after %s() eglError %s (0x%x)", - op, EGLUtils::strerror(error), error); - } -} - -static void checkGlError(const char* op) { - for (GLint error = glGetError(); error; error - = glGetError()) { - testPrintE("after %s() glError (0x%x)", op, error); - } -} - -static void printEGLConfiguration(EGLDisplay dpy, EGLConfig config) { - -#define X(VAL) {VAL, #VAL} - struct {EGLint attribute; const char* name;} names[] = { - X(EGL_BUFFER_SIZE), - X(EGL_ALPHA_SIZE), - X(EGL_BLUE_SIZE), - X(EGL_GREEN_SIZE), - X(EGL_RED_SIZE), - X(EGL_DEPTH_SIZE), - X(EGL_STENCIL_SIZE), - X(EGL_CONFIG_CAVEAT), - X(EGL_CONFIG_ID), - X(EGL_LEVEL), - X(EGL_MAX_PBUFFER_HEIGHT), - X(EGL_MAX_PBUFFER_PIXELS), - X(EGL_MAX_PBUFFER_WIDTH), - X(EGL_NATIVE_RENDERABLE), - X(EGL_NATIVE_VISUAL_ID), - X(EGL_NATIVE_VISUAL_TYPE), - X(EGL_SAMPLES), - X(EGL_SAMPLE_BUFFERS), - X(EGL_SURFACE_TYPE), - X(EGL_TRANSPARENT_TYPE), - X(EGL_TRANSPARENT_RED_VALUE), - X(EGL_TRANSPARENT_GREEN_VALUE), - X(EGL_TRANSPARENT_BLUE_VALUE), - X(EGL_BIND_TO_TEXTURE_RGB), - X(EGL_BIND_TO_TEXTURE_RGBA), - X(EGL_MIN_SWAP_INTERVAL), - X(EGL_MAX_SWAP_INTERVAL), - X(EGL_LUMINANCE_SIZE), - X(EGL_ALPHA_MASK_SIZE), - X(EGL_COLOR_BUFFER_TYPE), - X(EGL_RENDERABLE_TYPE), - X(EGL_CONFORMANT), - }; -#undef X - - for (size_t j = 0; j < sizeof(names) / sizeof(names[0]); j++) { - EGLint value = -1; - EGLint returnVal = eglGetConfigAttrib(dpy, config, names[j].attribute, &value); - EGLint error = eglGetError(); - if (returnVal && error == EGL_SUCCESS) { - testPrintI(" %s: %d (%#x)", names[j].name, value, value); - } - } - testPrintI(""); -} - -static void printGLString(const char *name, GLenum s) -{ - const char *v = (const char *) glGetString(s); - - if (v == NULL) { - testPrintI("GL %s unknown", name); - } else { - testPrintI("GL %s = %s", name, v); - } -} - -/* - * createLayerList - * dynamically creates layer list with numLayers worth - * of hwLayers entries. - */ -static hwc_layer_list_t *createLayerList(size_t numLayers) -{ - hwc_layer_list_t *list; - - size_t size = sizeof(hwc_layer_list) + numLayers * sizeof(hwc_layer_t); - if ((list = (hwc_layer_list_t *) calloc(1, size)) == NULL) { - return NULL; - } - list->flags = HWC_GEOMETRY_CHANGED; - list->numHwLayers = numLayers; - - return list; -} - -/* - * freeLayerList - * Frees memory previous allocated via createLayerList(). - */ -static void freeLayerList(hwc_layer_list_t *list) -{ - free(list); -} - -static void fillColor(GraphicBuffer *gBuf, RGBColor color, float trans) -{ - unsigned char* buf = NULL; - status_t err; - uint32_t pixel; - - // RGB 2 YUV conversion ratios - const struct rgb2yuvRatios { - int format; - float weightRed; - float weightBlu; - float weightGrn; - } rgb2yuvRatios[] = { - { HAL_PIXEL_FORMAT_YV12, 0.299, 0.114, 0.587 }, - }; - - const struct rgbAttrib { - int format; - bool hostByteOrder; - size_t bytes; - size_t rOffset; - size_t rSize; - size_t gOffset; - size_t gSize; - size_t bOffset; - size_t bSize; - size_t aOffset; - size_t aSize; - } rgbAttributes[] = { - {HAL_PIXEL_FORMAT_RGBA_8888, false, 4, 0, 8, 8, 8, 16, 8, 24, 8}, - {HAL_PIXEL_FORMAT_RGBX_8888, false, 4, 0, 8, 8, 8, 16, 8, 0, 0}, - {HAL_PIXEL_FORMAT_RGB_888, false, 3, 0, 8, 8, 8, 16, 8, 0, 0}, - {HAL_PIXEL_FORMAT_RGB_565, true, 2, 0, 5, 5, 6, 11, 5, 0, 0}, - {HAL_PIXEL_FORMAT_BGRA_8888, false, 4, 16, 8, 8, 8, 0, 8, 24, 8}, - {HAL_PIXEL_FORMAT_RGBA_5551, true , 2, 0, 5, 5, 5, 10, 5, 15, 1}, - {HAL_PIXEL_FORMAT_RGBA_4444, false, 2, 12, 4, 0, 4, 4, 4, 8, 4}, - }; - - // If YUV format, convert color and pass work to YUV color fill - for (unsigned int n1 = 0; n1 < NUMA(rgb2yuvRatios); n1++) { - if (gBuf->getPixelFormat() == rgb2yuvRatios[n1].format) { - float wr = rgb2yuvRatios[n1].weightRed; - float wb = rgb2yuvRatios[n1].weightBlu; - float wg = rgb2yuvRatios[n1].weightGrn; - float y = wr * color.r() + wb * color.b() + wg * color.g(); - float u = 0.5 * ((color.b() - y) / (1 - wb)) + 0.5; - float v = 0.5 * ((color.r() - y) / (1 - wr)) + 0.5; - YUVColor yuvColor(y, u, v); - fillColor(gBuf, yuvColor, trans); - return; - } - } - - const struct rgbAttrib *attrib; - for (attrib = rgbAttributes; attrib < rgbAttributes + NUMA(rgbAttributes); - attrib++) { - if (attrib->format == gBuf->getPixelFormat()) { break; } - } - if (attrib >= rgbAttributes + NUMA(rgbAttributes)) { - testPrintE("fillColor rgb unsupported format of: %u", - gBuf->getPixelFormat()); - exit(50); - } - - pixel = htonl((uint32_t) (((1 << attrib->rSize) - 1) * color.r()) - << ((sizeof(pixel) * BITSPERBYTE) - - (attrib->rOffset + attrib->rSize))); - pixel |= htonl((uint32_t) (((1 << attrib->gSize) - 1) * color.g()) - << ((sizeof(pixel) * BITSPERBYTE) - - (attrib->gOffset + attrib->gSize))); - pixel |= htonl((uint32_t) (((1 << attrib->bSize) - 1) * color.b()) - << ((sizeof(pixel) * BITSPERBYTE) - - (attrib->bOffset + attrib->bSize))); - if (attrib->aSize) { - pixel |= htonl((uint32_t) (((1 << attrib->aSize) - 1) * trans) - << ((sizeof(pixel) * BITSPERBYTE) - - (attrib->aOffset + attrib->aSize))); - } - if (attrib->hostByteOrder) { - pixel = ntohl(pixel); - pixel >>= sizeof(pixel) * BITSPERBYTE - attrib->bytes * BITSPERBYTE; - } - - err = gBuf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&buf)); - if (err != 0) { - testPrintE("fillColor rgb lock failed: %d", err); - exit(51); - } - - for (unsigned int row = 0; row < gBuf->getHeight(); row++) { - for (unsigned int col = 0; col < gBuf->getWidth(); col++) { - memmove(buf, &pixel, attrib->bytes); - buf += attrib->bytes; - } - for (unsigned int pad = 0; - pad < (gBuf->getStride() - gBuf->getWidth()) * attrib->bytes; - pad++) { - *buf++ = testRandMod(256); - } - } - - err = gBuf->unlock(); - if (err != 0) { - testPrintE("fillColor rgb unlock failed: %d", err); - exit(52); - } -} - -static void fillColor(GraphicBuffer *gBuf, YUVColor color, float trans) -{ - unsigned char* buf = NULL; - status_t err; - unsigned int width = gBuf->getWidth(); - unsigned int height = gBuf->getHeight(); - - const struct yuvAttrib { - int format; - bool planar; - unsigned int uSubSampX; - unsigned int uSubSampY; - unsigned int vSubSampX; - unsigned int vSubSampY; - } yuvAttributes[] = { - { HAL_PIXEL_FORMAT_YV12, true, 2, 2, 2, 2}, - }; - - const struct yuvAttrib *attrib; - for (attrib = yuvAttributes; attrib < yuvAttributes + NUMA(yuvAttributes); - attrib++) { - if (attrib->format == gBuf->getPixelFormat()) { break; } - } - if (attrib >= yuvAttributes + NUMA(yuvAttributes)) { - testPrintE("fillColor yuv unsupported format of: %u", - gBuf->getPixelFormat()); - exit(60); - } - - assert(attrib->planar == true); // So far, only know how to handle planar - - err = gBuf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&buf)); - if (err != 0) { - testPrintE("fillColor lock failed: %d", err); - exit(61); - } - - // Fill in Y component - for (unsigned int row = 0; row < height; row++) { - for (unsigned int col = 0; col < width; col++) { - *buf++ = 255 * color.y(); - } - for (unsigned int pad = 0; pad < gBuf->getStride() - gBuf->getWidth(); - pad++) { - *buf++ = testRandMod(256); - } - } - - // Fill in U component - for (unsigned int row = 0; row < height; row += attrib->uSubSampY) { - for (unsigned int col = 0; col < width; col += attrib->uSubSampX) { - *buf++ = 255 * color.u(); - } - for (unsigned int pad = 0; pad < gBuf->getStride() - gBuf->getWidth(); - pad += attrib->uSubSampX) { - *buf++ = testRandMod(256); - } - } - - // Fill in V component - for (unsigned int row = 0; row < height; row += attrib->vSubSampY) { - for (unsigned int col = 0; col < width; col += attrib->vSubSampX) { - *buf++ = 255 * color.v(); - } - for (unsigned int pad = 0; pad < gBuf->getStride() - gBuf->getWidth(); - pad += attrib->vSubSampX) { - *buf++ = testRandMod(256); - } - } - - err = gBuf->unlock(); - if (err != 0) { - testPrintE("fillColor unlock failed: %d", err); - exit(62); - } -} - void init(void) { - int rv; - - EGLBoolean returnValue; - EGLConfig myConfig = {0}; - EGLint contextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; - EGLint sConfigAttribs[] = { - EGL_SURFACE_TYPE, EGL_WINDOW_BIT, - EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, - EGL_NONE }; - EGLint majorVersion, minorVersion; - - checkEglError("<init>"); - dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); - checkEglError("eglGetDisplay"); - if (dpy == EGL_NO_DISPLAY) { - testPrintE("eglGetDisplay returned EGL_NO_DISPLAY"); - exit(70); - } + srand48(0); // Defensively set pseudo random number generator. + // Should not need to set this, because a stress test + // sets the seed on each pass. Defensively set it here + // so that future code that uses pseudo random numbers + // before the first pass will be deterministic. - returnValue = eglInitialize(dpy, &majorVersion, &minorVersion); - checkEglError("eglInitialize", returnValue); - testPrintI("EGL version %d.%d", majorVersion, minorVersion); - if (returnValue != EGL_TRUE) { - testPrintE("eglInitialize failed"); - exit(71); - } - - EGLNativeWindowType window = android_createDisplaySurface(); - if (window == NULL) { - testPrintE("android_createDisplaySurface failed"); - exit(72); - } - returnValue = EGLUtils::selectConfigForNativeWindow(dpy, - sConfigAttribs, window, &myConfig); - if (returnValue) { - testPrintE("EGLUtils::selectConfigForNativeWindow() returned %d", - returnValue); - exit(73); - } - checkEglError("EGLUtils::selectConfigForNativeWindow"); + hwcTestInitDisplay(verbose, &dpy, &surface, &width, &height); - testPrintI("Chose this configuration:"); - printEGLConfiguration(dpy, myConfig); - - surface = eglCreateWindowSurface(dpy, myConfig, window, NULL); - checkEglError("eglCreateWindowSurface"); - if (surface == EGL_NO_SURFACE) { - testPrintE("gelCreateWindowSurface failed."); - exit(74); - } - - context = eglCreateContext(dpy, myConfig, EGL_NO_CONTEXT, contextAttribs); - checkEglError("eglCreateContext"); - if (context == EGL_NO_CONTEXT) { - testPrintE("eglCreateContext failed"); - exit(75); - } - returnValue = eglMakeCurrent(dpy, surface, surface, context); - checkEglError("eglMakeCurrent", returnValue); - if (returnValue != EGL_TRUE) { - testPrintE("eglMakeCurrent failed"); - exit(76); - } - eglQuerySurface(dpy, surface, EGL_WIDTH, &width); - checkEglError("eglQuerySurface"); - eglQuerySurface(dpy, surface, EGL_HEIGHT, &height); - checkEglError("eglQuerySurface"); - - testPrintI("Window dimensions: %d x %d", width, height); - - printGLString("Version", GL_VERSION); - printGLString("Vendor", GL_VENDOR); - printGLString("Renderer", GL_RENDERER); - printGLString("Extensions", GL_EXTENSIONS); - - if ((rv = hw_get_module(HWC_HARDWARE_MODULE_ID, &hwcModule)) != 0) { - testPrintE("hw_get_module failed, rv: %i", rv); - errno = -rv; - perror(NULL); - exit(77); - } - if ((rv = hwc_open(hwcModule, &hwcDevice)) != 0) { - testPrintE("hwc_open failed, rv: %i", rv); - errno = -rv; - perror(NULL); - exit(78); - } - - testPrintI(""); + hwcTestOpenHwc(&hwcDevice); } /* @@ -1051,8 +564,9 @@ void initFrames(unsigned int seed) for (unsigned int row = 0; row < rows; row++) { // All frames within a row have to have the same format and // dimensions. Width and height need to be >= 1. - unsigned int formatIdx = testRandMod(NUMA(graphicFormat)); - const struct graphicFormat *formatPtr = &graphicFormat[formatIdx]; + unsigned int formatIdx = testRandMod(NUMA(hwcTestGraphicFormat)); + const struct hwcTestGraphicFormat *formatPtr + = &hwcTestGraphicFormat[formatIdx]; int format = formatPtr->format; // Pick width and height, which must be >= 1 and the size @@ -1069,164 +583,33 @@ void initFrames(unsigned int seed) } if (verbose) { testPrintI(" frame %u width: %u height: %u format: %u %s", - row, w, h, format, graphicFormat2str(format)); + row, w, h, format, hwcTestGraphicFormat2str(format)); } size_t cols = testRandMod((maxCols + 1) - minCols) + minCols; frames[row].resize(cols); for (unsigned int col = 0; col < cols; col++) { - RGBColor color(testRandFract(), testRandFract(), testRandFract()); - float transp = testRandFract(); + ColorFract color(testRandFract(), testRandFract(), testRandFract()); + float alpha = testRandFract(); frames[row][col] = new GraphicBuffer(w, h, format, texUsage); if ((rv = frames[row][col]->initCheck()) != NO_ERROR) { testPrintE("GraphicBuffer initCheck failed, rv: %i", rv); testPrintE(" frame %u width: %u height: %u format: %u %s", - row, w, h, format, graphicFormat2str(format)); + row, w, h, format, hwcTestGraphicFormat2str(format)); exit(80); } - fillColor(frames[row][col].get(), color, transp); + hwcTestFillColor(frames[row][col].get(), color, alpha); if (verbose) { - testPrintI(" buf: %p handle: %p color: <%f, %f, %f> " - "transp: %f", + testPrintI(" buf: %p handle: %p color: %s alpha: %f", frames[row][col].get(), frames[row][col]->handle, - color.r(), color.g(), color.b(), transp); + string(color).c_str(), alpha); } } } } -void displayList(hwc_layer_list_t *list) -{ - testPrintI(" flags: %#x%s", list->flags, - (list->flags & HWC_GEOMETRY_CHANGED) ? " GEOMETRY_CHANGED" : ""); - testPrintI(" numHwLayers: %u", list->numHwLayers); - - for (unsigned int layer = 0; layer < list->numHwLayers; layer++) { - testPrintI(" layer %u compositionType: %#x%s%s", layer, - list->hwLayers[layer].compositionType, - (list->hwLayers[layer].compositionType == HWC_FRAMEBUFFER) - ? " FRAMEBUFFER" : "", - (list->hwLayers[layer].compositionType == HWC_OVERLAY) - ? " OVERLAY" : ""); - - testPrintI(" hints: %#x", - list->hwLayers[layer].hints, - (list->hwLayers[layer].hints & HWC_HINT_TRIPLE_BUFFER) - ? " TRIPLE_BUFFER" : "", - (list->hwLayers[layer].hints & HWC_HINT_CLEAR_FB) - ? " CLEAR_FB" : ""); - - testPrintI(" flags: %#x%s", - list->hwLayers[layer].flags, - (list->hwLayers[layer].flags & HWC_SKIP_LAYER) - ? " SKIP_LAYER" : ""); - - testPrintI(" handle: %p", - list->hwLayers[layer].handle); - - // Intentionally skipped display of ROT_180 & ROT_270, - // which are formed from combinations of the other flags. - testPrintI(" transform: %#x%s%s%s", - list->hwLayers[layer].transform, - (list->hwLayers[layer].transform & HWC_TRANSFORM_FLIP_H) - ? " FLIP_H" : "", - (list->hwLayers[layer].transform & HWC_TRANSFORM_FLIP_V) - ? " FLIP_V" : "", - (list->hwLayers[layer].transform & HWC_TRANSFORM_ROT_90) - ? " ROT_90" : ""); - - testPrintI(" blending: %#x", - list->hwLayers[layer].blending, - (list->hwLayers[layer].blending == HWC_BLENDING_NONE) - ? " NONE" : "", - (list->hwLayers[layer].blending == HWC_BLENDING_PREMULT) - ? " PREMULT" : "", - (list->hwLayers[layer].blending == HWC_BLENDING_COVERAGE) - ? " COVERAGE" : ""); - - testPrintI(" sourceCrop: [%i, %i, %i, %i]", - list->hwLayers[layer].sourceCrop.left, - list->hwLayers[layer].sourceCrop.top, - list->hwLayers[layer].sourceCrop.right, - list->hwLayers[layer].sourceCrop.bottom); - - testPrintI(" displayFrame: [%i, %i, %i, %i]", - list->hwLayers[layer].displayFrame.left, - list->hwLayers[layer].displayFrame.top, - list->hwLayers[layer].displayFrame.right, - list->hwLayers[layer].displayFrame.bottom); - testPrintI(" scaleFactor: [%f %f]", - (float) (list->hwLayers[layer].displayFrame.right - - list->hwLayers[layer].displayFrame.left) - / (float) (list->hwLayers[layer].sourceCrop.right - - list->hwLayers[layer].sourceCrop.left), - (float) (list->hwLayers[layer].displayFrame.bottom - - list->hwLayers[layer].displayFrame.top) - / (float) (list->hwLayers[layer].sourceCrop.bottom - - list->hwLayers[layer].sourceCrop.top)); - } -} - -/* - * Display List Prepare Modifiable - * - * Displays the portions of a list that are meant to be modified by - * a prepare call. - */ -void displayListPrepareModifiable(hwc_layer_list_t *list) -{ - for (unsigned int layer = 0; layer < list->numHwLayers; layer++) { - testPrintI(" layer %u compositionType: %#x%s%s", layer, - list->hwLayers[layer].compositionType, - (list->hwLayers[layer].compositionType == HWC_FRAMEBUFFER) - ? " FRAMEBUFFER" : "", - (list->hwLayers[layer].compositionType == HWC_OVERLAY) - ? " OVERLAY" : ""); - testPrintI(" hints: %#x%s%s", - list->hwLayers[layer].hints, - (list->hwLayers[layer].hints & HWC_HINT_TRIPLE_BUFFER) - ? " TRIPLE_BUFFER" : "", - (list->hwLayers[layer].hints & HWC_HINT_CLEAR_FB) - ? " CLEAR_FB" : ""); - } -} - -/* - * Display List Handles - * - * Displays the handles of all the graphic buffers in the list. - */ -void displayListHandles(hwc_layer_list_t *list) -{ - const unsigned int maxLayersPerLine = 6; - - ostringstream str(" layers:"); - for (unsigned int layer = 0; layer < list->numHwLayers; layer++) { - str << ' ' << list->hwLayers[layer].handle; - if (((layer % maxLayersPerLine) == (maxLayersPerLine - 1)) - && (layer != list->numHwLayers - 1)) { - testPrintI("%s", str.str().c_str()); - str.str(" "); - } - } - testPrintI("%s", str.str().c_str()); -} - -const char *graphicFormat2str(unsigned int format) -{ - const static char *unknown = "unknown"; - - for (unsigned int n1 = 0; n1 < NUMA(graphicFormat); n1++) { - if (format == graphicFormat[n1].format) { - return graphicFormat[n1].desc; - } - } - - return unknown; -} - /* * Vector Random Select * diff --git a/opengl/tests/hwc/hwcTestLib.cpp b/opengl/tests/hwc/hwcTestLib.cpp new file mode 100644 index 0000000..575af89 --- /dev/null +++ b/opengl/tests/hwc/hwcTestLib.cpp @@ -0,0 +1,995 @@ +/* + * 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 Test Library + * Utility library functions for use by the Hardware Composer test cases + */ + +#include <sstream> +#include <string> + +#include <arpa/inet.h> // For ntohl() and htonl() + +#include <hwc/hwcTestLib.h> + +// Defines +#define NUMA(a) (sizeof(a) / sizeof(a [0])) + +// Function Prototypes +static void printGLString(const char *name, GLenum s); +static void checkEglError(const char* op, EGLBoolean returnVal = EGL_TRUE); +static void checkGlError(const char* op); +static void printEGLConfiguration(EGLDisplay dpy, EGLConfig config); + +using namespace std; +using namespace android; + + +#define BITSPERBYTE 8 // TODO: Obtain from <values.h>, once + // it has been added + +// Initialize Display +void hwcTestInitDisplay(bool verbose, EGLDisplay *dpy, EGLSurface *surface, + EGLint *width, EGLint *height) +{ + static EGLContext context; + + int rv; + + EGLBoolean returnValue; + EGLConfig myConfig = {0}; + EGLint contextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; + EGLint sConfigAttribs[] = { + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + EGL_NONE }; + EGLint majorVersion, minorVersion; + + checkEglError("<init>"); + *dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); + checkEglError("eglGetDisplay"); + if (*dpy == EGL_NO_DISPLAY) { + testPrintE("eglGetDisplay returned EGL_NO_DISPLAY"); + exit(70); + } + + returnValue = eglInitialize(*dpy, &majorVersion, &minorVersion); + checkEglError("eglInitialize", returnValue); + if (verbose) { + testPrintI("EGL version %d.%d", majorVersion, minorVersion); + } + if (returnValue != EGL_TRUE) { + testPrintE("eglInitialize failed"); + exit(71); + } + + EGLNativeWindowType window = android_createDisplaySurface(); + if (window == NULL) { + testPrintE("android_createDisplaySurface failed"); + exit(72); + } + returnValue = EGLUtils::selectConfigForNativeWindow(*dpy, + sConfigAttribs, window, &myConfig); + if (returnValue) { + testPrintE("EGLUtils::selectConfigForNativeWindow() returned %d", + returnValue); + exit(73); + } + checkEglError("EGLUtils::selectConfigForNativeWindow"); + + if (verbose) { + testPrintI("Chose this configuration:"); + printEGLConfiguration(*dpy, myConfig); + } + + *surface = eglCreateWindowSurface(*dpy, myConfig, window, NULL); + checkEglError("eglCreateWindowSurface"); + if (*surface == EGL_NO_SURFACE) { + testPrintE("gelCreateWindowSurface failed."); + exit(74); + } + + context = eglCreateContext(*dpy, myConfig, EGL_NO_CONTEXT, contextAttribs); + checkEglError("eglCreateContext"); + if (context == EGL_NO_CONTEXT) { + testPrintE("eglCreateContext failed"); + exit(75); + } + returnValue = eglMakeCurrent(*dpy, *surface, *surface, context); + checkEglError("eglMakeCurrent", returnValue); + if (returnValue != EGL_TRUE) { + testPrintE("eglMakeCurrent failed"); + exit(76); + } + eglQuerySurface(*dpy, *surface, EGL_WIDTH, width); + checkEglError("eglQuerySurface"); + eglQuerySurface(*dpy, *surface, EGL_HEIGHT, height); + checkEglError("eglQuerySurface"); + + if (verbose) { + testPrintI("Window dimensions: %d x %d", *width, *height); + + printGLString("Version", GL_VERSION); + printGLString("Vendor", GL_VENDOR); + printGLString("Renderer", GL_RENDERER); + printGLString("Extensions", GL_EXTENSIONS); + } +} + +// Open Hardware Composer Device +void hwcTestOpenHwc(hwc_composer_device_t **hwcDevicePtr) +{ + int rv; + hw_module_t const *hwcModule; + + if ((rv = hw_get_module(HWC_HARDWARE_MODULE_ID, &hwcModule)) != 0) { + testPrintE("hw_get_module failed, rv: %i", rv); + errno = -rv; + perror(NULL); + exit(77); + } + if ((rv = hwc_open(hwcModule, hwcDevicePtr)) != 0) { + testPrintE("hwc_open failed, rv: %i", rv); + errno = -rv; + perror(NULL); + exit(78); + } +} + +// Color fraction class to string conversion +ColorFract::operator string() +{ + ostringstream out; + + out << '[' << this->c1() << ", " + << this->c2() << ", " + << this->c3() << ']'; + + return out.str(); +} + +// Dimension class to string conversion +HwcTestDim::operator string() +{ + ostringstream out; + + out << '[' << this->width() << ", " + << this->height() << ']'; + + return out.str(); +} + +// Hardware Composer rectangle to string conversion +string hwcTestRect2str(const struct hwc_rect& rect) +{ + ostringstream out; + + out << '['; + out << rect.left << ", "; + out << rect.top << ", "; + out << rect.right << ", "; + out << rect.bottom; + out << ']'; + + return out.str(); +} + +// Parse HWC rectangle description of form [left, top, right, bottom] +struct hwc_rect hwcTestParseHwcRect(istringstream& in, bool& error) +{ + struct hwc_rect rect; + char chStart, ch; + + // Defensively specify that an error occurred. Will clear + // error flag if all of parsing succeeds. + error = true; + + // First character should be a [ or < + in >> chStart; + if (!in || ((chStart != '<') && (chStart != '['))) { return rect; } + + // Left + in >> rect.left; + if (!in) { return rect; } + in >> ch; + if (!in || (ch != ',')) { return rect; } + + // Top + in >> rect.top; + if (!in) { return rect; } + in >> ch; + if (!in || (ch != ',')) { return rect; } + + // Right + in >> rect.right; + if (!in) { return rect; } + in >> ch; + if (!in || (ch != ',')) { return rect; } + + // Bottom + in >> rect.bottom; + if (!in) { return rect; } + + // Closing > or ] + in >> ch; + if (!in) { return rect; } + if (((chStart == '<') && (ch != '>')) + || ((chStart == '[') && (ch != ']'))) { return rect; } + + // Validate right and bottom are greater than left and top + if ((rect.right <= rect.left) || (rect.bottom <= rect.top)) { return rect; } + + // Made It, clear error indicator + error = false; + + return rect; +} + +// Parse dimension of form [width, height] +HwcTestDim hwcTestParseDim(istringstream& in, bool& error) +{ + HwcTestDim dim; + char chStart, ch; + uint32_t val; + + // Defensively specify that an error occurred. Will clear + // error flag if all of parsing succeeds. + error = true; + + // First character should be a [ or < + in >> chStart; + if (!in || ((chStart != '<') && (chStart != '['))) { return dim; } + + // Width + in >> val; + if (!in) { return dim; } + dim.setWidth(val); + in >> ch; + if (!in || (ch != ',')) { return dim; } + + // Height + in >> val; + if (!in) { return dim; } + dim.setHeight(val); + + // Closing > or ] + in >> ch; + if (!in) { return dim; } + if (((chStart == '<') && (ch != '>')) + || ((chStart == '[') && (ch != ']'))) { return dim; } + + // Validate width and height greater than 0 + if ((dim.width() <= 0) || (dim.height() <= 0)) { return dim; } + + // Made It, clear error indicator + error = false; + return dim; +} + +// Parse fractional color of form [0.##, 0.##, 0.##] +// Fractional values can be from 0.0 to 1.0 inclusive. Note, integer +// values of 0.0 and 1.0, which are non-fractional, are considered valid. +// They are an exception, all other valid inputs are fractions. +ColorFract hwcTestParseColor(istringstream& in, bool& error) +{ + ColorFract color; + char chStart, ch; + float c1, c2, c3; + + // Defensively specify that an error occurred. Will clear + // error flag if all of parsing succeeds. + error = true; + + // First character should be a [ or < + in >> chStart; + if (!in || ((chStart != '<') && (chStart != '['))) { return color; } + + // 1st Component + in >> c1; + if (!in) { return color; } + if ((c1 < 0.0) || (c1 > 1.0)) { return color; } + in >> ch; + if (!in || (ch != ',')) { return color; } + + // 2nd Component + in >> c2; + if (!in) { return color; } + if ((c2 < 0.0) || (c2 > 1.0)) { return color; } + in >> ch; + if (!in || (ch != ',')) { return color; } + + // 3rd Component + in >> c3; + if (!in) { return color; } + if ((c3 < 0.0) || (c3 > 1.0)) { return color; } + + // Closing > or ] + in >> ch; + if (!in) { return color; } + if (((chStart == '<') && (ch != '>')) + || ((chStart == '[') && (ch != ']'))) { return color; } + + // Are all the components fractional + if ((c1 < 0.0) || (c1 > 1.0) + || (c2 < 0.0) || (c2 > 1.0) + || (c3 < 0.0) || (c3 > 1.0)) { return color; } + + // Made It, clear error indicator + error = false; + + return ColorFract(c1, c2, c3); +} + +// Look up and return pointer to structure with the characteristics +// of the graphic format named by the desc parameter. Search failure +// indicated by the return of NULL. +const struct hwcTestGraphicFormat *hwcTestGraphicFormatLookup(const char *desc) +{ + for (unsigned int n1 = 0; n1 < NUMA(hwcTestGraphicFormat); n1++) { + if (string(desc) == string(hwcTestGraphicFormat[n1].desc)) { + return &hwcTestGraphicFormat[n1]; + } + } + + return NULL; +} + +// Given the integer ID of a graphic format, return a pointer to +// a string that describes the format. +const char *hwcTestGraphicFormat2str(uint32_t format) +{ + const static char *unknown = "unknown"; + + for (unsigned int n1 = 0; n1 < NUMA(hwcTestGraphicFormat); n1++) { + if (format == hwcTestGraphicFormat[n1].format) { + return hwcTestGraphicFormat[n1].desc; + } + } + + return unknown; +} + +/* + * hwcTestCreateLayerList + * Dynamically creates layer list with numLayers worth + * of hwLayers entries. + */ +hwc_layer_list_t *hwcTestCreateLayerList(size_t numLayers) +{ + hwc_layer_list_t *list; + + size_t size = sizeof(hwc_layer_list) + numLayers * sizeof(hwc_layer_t); + if ((list = (hwc_layer_list_t *) calloc(1, size)) == NULL) { + return NULL; + } + list->flags = HWC_GEOMETRY_CHANGED; + list->numHwLayers = numLayers; + + return list; +} + +/* + * hwcTestFreeLayerList + * Frees memory previous allocated via hwcTestCreateLayerList(). + */ +void hwcTestFreeLayerList(hwc_layer_list_t *list) +{ + free(list); +} + +// Display the settings of the layer list pointed to by list +void hwcTestDisplayList(hwc_layer_list_t *list) +{ + testPrintI(" flags: %#x%s", list->flags, + (list->flags & HWC_GEOMETRY_CHANGED) ? " GEOMETRY_CHANGED" : ""); + testPrintI(" numHwLayers: %u", list->numHwLayers); + + for (unsigned int layer = 0; layer < list->numHwLayers; layer++) { + testPrintI(" layer %u compositionType: %#x%s%s", layer, + list->hwLayers[layer].compositionType, + (list->hwLayers[layer].compositionType == HWC_FRAMEBUFFER) + ? " FRAMEBUFFER" : "", + (list->hwLayers[layer].compositionType == HWC_OVERLAY) + ? " OVERLAY" : ""); + + testPrintI(" hints: %#x", + list->hwLayers[layer].hints, + (list->hwLayers[layer].hints & HWC_HINT_TRIPLE_BUFFER) + ? " TRIPLE_BUFFER" : "", + (list->hwLayers[layer].hints & HWC_HINT_CLEAR_FB) + ? " CLEAR_FB" : ""); + + testPrintI(" flags: %#x%s", + list->hwLayers[layer].flags, + (list->hwLayers[layer].flags & HWC_SKIP_LAYER) + ? " SKIP_LAYER" : ""); + + testPrintI(" handle: %p", + list->hwLayers[layer].handle); + + // Intentionally skipped display of ROT_180 & ROT_270, + // which are formed from combinations of the other flags. + testPrintI(" transform: %#x%s%s%s", + list->hwLayers[layer].transform, + (list->hwLayers[layer].transform & HWC_TRANSFORM_FLIP_H) + ? " FLIP_H" : "", + (list->hwLayers[layer].transform & HWC_TRANSFORM_FLIP_V) + ? " FLIP_V" : "", + (list->hwLayers[layer].transform & HWC_TRANSFORM_ROT_90) + ? " ROT_90" : ""); + + testPrintI(" blending: %#x%s%s%s", + list->hwLayers[layer].blending, + (list->hwLayers[layer].blending == HWC_BLENDING_NONE) + ? " NONE" : "", + (list->hwLayers[layer].blending == HWC_BLENDING_PREMULT) + ? " PREMULT" : "", + (list->hwLayers[layer].blending == HWC_BLENDING_COVERAGE) + ? " COVERAGE" : ""); + + testPrintI(" sourceCrop: %s", + hwcTestRect2str(list->hwLayers[layer].sourceCrop).c_str()); + testPrintI(" displayFrame: %s", + hwcTestRect2str(list->hwLayers[layer].displayFrame).c_str()); + testPrintI(" scaleFactor: [%f, %f]", + (float) (list->hwLayers[layer].displayFrame.right + - list->hwLayers[layer].displayFrame.left) + / (float) (list->hwLayers[layer].sourceCrop.right + - list->hwLayers[layer].sourceCrop.left), + (float) (list->hwLayers[layer].displayFrame.bottom + - list->hwLayers[layer].displayFrame.top) + / (float) (list->hwLayers[layer].sourceCrop.bottom + - list->hwLayers[layer].sourceCrop.top)); + } +} + +/* + * Display List Prepare Modifiable + * + * Displays the portions of a list that are meant to be modified by + * a prepare call. + */ +void hwcTestDisplayListPrepareModifiable(hwc_layer_list_t *list) +{ + for (unsigned int layer = 0; layer < list->numHwLayers; layer++) { + testPrintI(" layer %u compositionType: %#x%s%s", layer, + list->hwLayers[layer].compositionType, + (list->hwLayers[layer].compositionType == HWC_FRAMEBUFFER) + ? " FRAMEBUFFER" : "", + (list->hwLayers[layer].compositionType == HWC_OVERLAY) + ? " OVERLAY" : ""); + testPrintI(" hints: %#x%s%s", + list->hwLayers[layer].hints, + (list->hwLayers[layer].hints & HWC_HINT_TRIPLE_BUFFER) + ? " TRIPLE_BUFFER" : "", + (list->hwLayers[layer].hints & HWC_HINT_CLEAR_FB) + ? " CLEAR_FB" : ""); + } +} + +/* + * Display List Handles + * + * Displays the handles of all the graphic buffers in the list. + */ +void hwcTestDisplayListHandles(hwc_layer_list_t *list) +{ + const unsigned int maxLayersPerLine = 6; + + ostringstream str(" layers:"); + for (unsigned int layer = 0; layer < list->numHwLayers; layer++) { + str << ' ' << list->hwLayers[layer].handle; + if (((layer % maxLayersPerLine) == (maxLayersPerLine - 1)) + && (layer != list->numHwLayers - 1)) { + testPrintI("%s", str.str().c_str()); + str.str(" "); + } + } + testPrintI("%s", str.str().c_str()); +} + +// Returns a uint32_t that contains a format specific representation of a +// single pixel of the given color and alpha values. +uint32_t hwcTestColor2Pixel(uint32_t format, ColorFract color, float alpha) +{ + const struct attrib { + uint32_t format; + bool hostByteOrder; + size_t bytes; + size_t c1Offset; + size_t c1Size; + size_t c2Offset; + size_t c2Size; + size_t c3Offset; + size_t c3Size; + size_t aOffset; + size_t aSize; + } attributes[] = { + {HAL_PIXEL_FORMAT_RGBA_8888, false, 4, 0, 8, 8, 8, 16, 8, 24, 8}, + {HAL_PIXEL_FORMAT_RGBX_8888, false, 4, 0, 8, 8, 8, 16, 8, 0, 0}, + {HAL_PIXEL_FORMAT_RGB_888, false, 3, 0, 8, 8, 8, 16, 8, 0, 0}, + {HAL_PIXEL_FORMAT_RGB_565, true, 2, 0, 5, 5, 6, 11, 5, 0, 0}, + {HAL_PIXEL_FORMAT_BGRA_8888, false, 4, 16, 8, 8, 8, 0, 8, 24, 8}, + {HAL_PIXEL_FORMAT_RGBA_5551, true , 2, 0, 5, 5, 5, 10, 5, 15, 1}, + {HAL_PIXEL_FORMAT_RGBA_4444, false, 2, 12, 4, 0, 4, 4, 4, 8, 4}, + {HAL_PIXEL_FORMAT_YV12, true, 3, 16, 8, 8, 8, 0, 8, 0, 0}, + }; + + const struct attrib *attrib; + for (attrib = attributes; attrib < attributes + NUMA(attributes); + attrib++) { + if (attrib->format == format) { break; } + } + if (attrib >= attributes + NUMA(attributes)) { + testPrintE("colorFract2Pixel unsupported format of: %u", format); + exit(80); + } + + uint32_t pixel; + pixel = htonl((uint32_t) round((((1 << attrib->c1Size) - 1) * color.c1())) + << ((sizeof(pixel) * BITSPERBYTE) + - (attrib->c1Offset + attrib->c1Size))); + pixel |= htonl((uint32_t) round((((1 << attrib->c2Size) - 1) * color.c2())) + << ((sizeof(pixel) * BITSPERBYTE) + - (attrib->c2Offset + attrib->c2Size))); + pixel |= htonl((uint32_t) round((((1 << attrib->c3Size) - 1) * color.c3())) + << ((sizeof(pixel) * BITSPERBYTE) + - (attrib->c3Offset + attrib->c3Size))); + if (attrib->aSize) { + pixel |= htonl((uint32_t) round((((1 << attrib->aSize) - 1) * alpha)) + << ((sizeof(pixel) * BITSPERBYTE) + - (attrib->aOffset + attrib->aSize))); + } + if (attrib->hostByteOrder) { + pixel = ntohl(pixel); + pixel >>= sizeof(pixel) * BITSPERBYTE - attrib->bytes * BITSPERBYTE; + } + + return pixel; +} + +// Sets the pixel at the given x and y coordinates to the color and alpha +// value given by pixel. The contents of pixel is format specific. It's +// value should come from a call to hwcTestColor2Pixel(). +void hwcTestSetPixel(GraphicBuffer *gBuf, unsigned char *buf, + uint32_t x, uint32_t y, uint32_t pixel) +{ + + const struct attrib { + int format; + size_t bytes; + } attributes[] = { + {HAL_PIXEL_FORMAT_RGBA_8888, 4}, + {HAL_PIXEL_FORMAT_RGBX_8888, 4}, + {HAL_PIXEL_FORMAT_RGB_888, 3}, + {HAL_PIXEL_FORMAT_RGB_565, 2}, + {HAL_PIXEL_FORMAT_BGRA_8888, 4}, + {HAL_PIXEL_FORMAT_RGBA_5551, 2}, + {HAL_PIXEL_FORMAT_RGBA_4444, 2}, + }; + + if (gBuf->getPixelFormat() == HAL_PIXEL_FORMAT_YV12) { + uint32_t yPlaneOffset, uPlaneOffset, vPlaneOffset; + uint32_t yPlaneStride = gBuf->getStride(); + uint32_t uPlaneStride = ((gBuf->getStride() / 2) + 0xf) & ~0xf; + uint32_t vPlaneStride = uPlaneStride; + yPlaneOffset = 0; + vPlaneOffset = yPlaneOffset + yPlaneStride * gBuf->getHeight(); + uPlaneOffset = vPlaneOffset + + vPlaneStride * (gBuf->getHeight() / 2); + *(buf + yPlaneOffset + y * yPlaneStride + x) = pixel & 0xff; + *(buf + uPlaneOffset + (y / 2) * uPlaneStride + (x / 2)) + = (pixel & 0xff00) >> 8; + *(buf + vPlaneOffset + (y / 2) * vPlaneStride + (x / 2)) + = (pixel & 0xff0000) >> 16; + + return; + } + + const struct attrib *attrib; + for (attrib = attributes; attrib < attributes + NUMA(attributes); + attrib++) { + if (attrib->format == gBuf->getPixelFormat()) { break; } + } + if (attrib >= attributes + NUMA(attributes)) { + testPrintE("setPixel unsupported format of: %u", + gBuf->getPixelFormat()); + exit(90); + } + + memmove(buf + ((gBuf->getStride() * attrib->bytes) * y) + + (attrib->bytes * x), &pixel, attrib->bytes); +} + +// Fill a given graphic buffer with a uniform color and alpha +void hwcTestFillColor(GraphicBuffer *gBuf, ColorFract color, float alpha) +{ + unsigned char* buf = NULL; + status_t err; + uint32_t pixel; + + pixel = hwcTestColor2Pixel(gBuf->getPixelFormat(), color, alpha); + + err = gBuf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&buf)); + if (err != 0) { + testPrintE("hwcTestFillColor lock failed: %d", err); + exit(100); + } + + for (unsigned int x = 0; x < gBuf->getStride(); x++) { + for (unsigned int y = 0; y < gBuf->getHeight(); y++) { + uint32_t val = pixel; + hwcTestSetPixel(gBuf, buf, x, y, (x < gBuf->getWidth()) + ? pixel : testRand()); + } + } + + err = gBuf->unlock(); + if (err != 0) { + testPrintE("hwcTestFillColor unlock failed: %d", err); + exit(101); + } +} + +// Fill the given buffer with a horizontal blend of colors, with the left +// side color given by startColor and the right side color given by +// endColor. The startColor and endColor values are specified in the format +// given by colorFormat, which might be different from the format of the +// graphic buffer. When different, a color conversion is done when possible +// to the graphic format of the graphic buffer. A color of black is +// produced for cases where the conversion is impossible (e.g. out of gamut +// values). +void hwcTestFillColorHBlend(GraphicBuffer *gBuf, uint32_t colorFormat, + ColorFract startColor, ColorFract endColor) +{ + status_t err; + unsigned char* buf = NULL; + const uint32_t width = gBuf->getWidth(); + const uint32_t height = gBuf->getHeight(); + const uint32_t stride = gBuf->getStride(); + + err = gBuf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&buf)); + if (err != 0) { + testPrintE("hwcTestFillColorHBlend lock failed: %d", err); + exit(110); + } + + for (unsigned int x = 0; x < stride; x++) { + uint32_t pixel; + if (x < width) { + ColorFract color(startColor.c1() + (endColor.c1() - startColor.c1()) + * ((float) x / (float) (width - 1)), + startColor.c2() + (endColor.c2() - startColor.c2()) + * ((float) x / (float) (width - 1)), + startColor.c3() + (endColor.c3() - startColor.c3()) + * ((float) x / (float) (width - 1))); + + // When formats differ, convert colors. + // Important to not convert when formats are the same, since + // out of gamut colors are always converted to black. + if (colorFormat != (uint32_t) gBuf->getPixelFormat()) { + hwcTestColorConvert(colorFormat, gBuf->getPixelFormat(), color); + } + pixel = hwcTestColor2Pixel(gBuf->getPixelFormat(), color, 1.0); + } else { + // Fill pad with random values + pixel = testRand(); + } + + for (unsigned int y = 0; y <= height; y++) { + hwcTestSetPixel(gBuf, buf, x, y, pixel); + } + } + + err = gBuf->unlock(); + if (err != 0) { + testPrintE("hwcTestFillColorHBlend unlock failed: %d", err); + exit(111); + } +} + +/* + * When possible, converts color specified as a full range value in + * the fromFormat, into an equivalent full range color in the toFormat. + * When conversion is impossible (e.g. out of gamut color) a color + * or black in the full range output format is produced. The input + * color is given as a fractional color in the parameter named color. + * The produced color is written over the same parameter used to + * provide the input color. + * + * Each graphic format has 3 color components and each of these + * components has both a full and in gamut range. This function uses + * a table that provides the full and in gamut ranges of each of the + * supported graphic formats. The full range is given by members named + * c[123]Min to c[123]Max, while the in gamut range is given by members + * named c[123]Low to c[123]High. In most cases the full and in gamut + * ranges are equivalent. This occurs when the c[123]Min == c[123]Low and + * c[123]High == c[123]Max. + * + * The input and produced colors are both specified as a fractional amount + * of the full range. The diagram below provides an overview of the + * conversion process. The main steps are: + * + * 1. Produce black if the input color is out of gamut. + * + * 2. Convert the in gamut color into the fraction of the fromFromat + * in gamut range. + * + * 3. Convert from the fraction of the in gamut from format range to + * the fraction of the in gamut to format range. Produce black + * if an equivalent color does not exists. + * + * 4. Covert from the fraction of the in gamut to format to the + * fraction of the full range to format. + * + * From Format To Format + * max high high max + * ----+ +-----------+ + * high \ / \ high + * ------\-------------+ +--------> + * \ + * \ +--- black --+ + * \ / \ + * \ / +--> + * low \ / low + * -------- ---+-- black --+ + * min low low min + * ^ ^ ^ ^ ^ + * | | | | | + * | | | | +-- fraction of full range + * | | | +-- fraction of valid range + * | | +-- fromFormat to toFormat color conversion + * | +-- fraction of valid range + * +-- fraction of full range + */ +void hwcTestColorConvert(uint32_t fromFormat, uint32_t toFormat, + ColorFract& color) +{ + const struct attrib { + uint32_t format; + bool rgb; + bool yuv; + int c1Min, c1Low, c1High, c1Max; + int c2Min, c2Low, c2High, c2Max; + int c3Min, c3Low, c3High, c3Max; + } attributes[] = { + {HAL_PIXEL_FORMAT_RGBA_8888, true, false, + 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255}, + {HAL_PIXEL_FORMAT_RGBX_8888, true, false, + 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255}, + {HAL_PIXEL_FORMAT_RGB_888, true, false, + 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255}, + {HAL_PIXEL_FORMAT_RGB_565, true, false, + 0, 0, 31, 31, 0, 0, 63, 63, 0, 0, 31, 31}, + {HAL_PIXEL_FORMAT_BGRA_8888, true, false, + 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255}, + {HAL_PIXEL_FORMAT_RGBA_5551, true, false, + 0, 0, 31, 31, 0, 0, 31, 31, 0, 0, 31, 31}, + {HAL_PIXEL_FORMAT_RGBA_4444, true, false, + 0, 0, 15, 15, 0, 0, 15, 15, 0, 0, 15, 15}, + {HAL_PIXEL_FORMAT_YV12, false, true, + 0, 16, 235, 255, 0, 16, 240, 255, 0, 16, 240, 255}, + }; + + const struct attrib *fromAttrib; + for (fromAttrib = attributes; fromAttrib < attributes + NUMA(attributes); + fromAttrib++) { + if (fromAttrib->format == fromFormat) { break; } + } + if (fromAttrib >= attributes + NUMA(attributes)) { + testPrintE("hwcTestColorConvert unsupported from format of: %u", + fromFormat); + exit(120); + } + + const struct attrib *toAttrib; + for (toAttrib = attributes; toAttrib < attributes + NUMA(attributes); + toAttrib++) { + if (toAttrib->format == toFormat) { break; } + } + if (toAttrib >= attributes + NUMA(attributes)) { + testPrintE("hwcTestColorConvert unsupported to format of: %u", + toFormat); + exit(121); + } + + // Produce black if any of the from components are outside the + // valid color range + float c1Val = fromAttrib->c1Min + + ((float) (fromAttrib->c1Max - fromAttrib->c1Min) * color.c1()); + float c2Val = fromAttrib->c2Min + + ((float) (fromAttrib->c2Max - fromAttrib->c2Min) * color.c2()); + float c3Val = fromAttrib->c3Min + + ((float) (fromAttrib->c3Max - fromAttrib->c3Min) * color.c3()); + if ((c1Val < fromAttrib->c1Low) || (c1Val > fromAttrib->c1High) + || (c2Val < fromAttrib->c2Low) || (c2Val > fromAttrib->c2High) + || (c3Val < fromAttrib->c3Low) || (c3Val > fromAttrib->c3High)) { + + // Return black + // Will use representation of black from RGBA8888 graphic format + // and recursively convert it to the requested graphic format. + color = ColorFract(0.0, 0.0, 0.0); + hwcTestColorConvert(HAL_PIXEL_FORMAT_RGBA_8888, toFormat, color); + return; + } + + // Within from format, convert from fraction of full range + // to fraction of valid range + color = ColorFract((c1Val - fromAttrib->c1Low) + / (fromAttrib->c1High - fromAttrib->c1Low), + (c2Val - fromAttrib->c2Low) + / (fromAttrib->c2High - fromAttrib->c2Low), + (c3Val - fromAttrib->c3Low) + / (fromAttrib->c3High - fromAttrib->c3Low)); + + // If needed perform RGB to YUV conversion + float wr = 0.2126, wg = 0.7152, wb = 0.0722; // ITU709 recommended constants + if (fromAttrib->rgb && toAttrib->yuv) { + float r = color.c1(), g = color.c2(), b = color.c3(); + float y = wr * r + wg * g + wb * b; + float u = 0.5 * ((b - y) / (1.0 - wb)) + 0.5; + float v = 0.5 * ((r - y) / (1.0 - wr)) + 0.5; + + // Produce black if color is outside the YUV gamut + if ((y < 0.0) || (y > 1.0) + || (u < 0.0) || (u > 1.0) + || (v < 0.0) || (v > 1.0)) { + y = 0.0; + u = v = 0.5; + } + + color = ColorFract(y, u, v); + } + + // If needed perform YUV to RGB conversion + // Equations determined from the ITU709 equations for RGB to YUV + // conversion, plus the following algebra: + // + // u = 0.5 * ((b - y) / (1.0 - wb)) + 0.5 + // 0.5 * ((b - y) / (1.0 - wb)) = u - 0.5 + // (b - y) / (1.0 - wb) = 2 * (u - 0.5) + // b - y = 2 * (u - 0.5) * (1.0 - wb) + // b = 2 * (u - 0.5) * (1.0 - wb) + y + // + // v = 0.5 * ((r -y) / (1.0 - wr)) + 0.5 + // 0.5 * ((r - y) / (1.0 - wr)) = v - 0.5 + // (r - y) / (1.0 - wr) = 2 * (v - 0.5) + // r - y = 2 * (v - 0.5) * (1.0 - wr) + // r = 2 * (v - 0.5) * (1.0 - wr) + y + // + // y = wr * r + wg * g + wb * b + // wr * r + wg * g + wb * b = y + // wg * g = y - wr * r - wb * b + // g = (y - wr * r - wb * b) / wg + if (fromAttrib->yuv && toAttrib->rgb) { + float y = color.c1(), u = color.c2(), v = color.c3(); + float r = 2.0 * (v - 0.5) * (1.0 - wr) + y; + float b = 2.0 * (u - 0.5) * (1.0 - wb) + y; + float g = (y - wr * r - wb * b) / wg; + + // Produce black if color is outside the RGB gamut + if ((r < 0.0) || (r > 1.0) + || (g < 0.0) || (g > 1.0) + || (b < 0.0) || (b > 1.0)) { + r = g = b = 0.0; + } + + color = ColorFract(r, g, b); + } + + // Within to format, convert from fraction of valid range + // to fraction of full range + c1Val = (toAttrib->c1Low + + (float) (toAttrib->c1High - toAttrib->c1Low) * color.c1()); + c2Val = (toAttrib->c1Low + + (float) (toAttrib->c2High - toAttrib->c2Low) * color.c2()); + c3Val = (toAttrib->c1Low + + (float) (toAttrib->c3High - toAttrib->c3Low) * color.c3()); + color = ColorFract((float) (c1Val - toAttrib->c1Min) + / (float) (toAttrib->c1Max - toAttrib->c1Min), + (float) (c2Val - toAttrib->c2Min) + / (float) (toAttrib->c2Max - toAttrib->c2Min), + (float) (c3Val - toAttrib->c3Min) + / (float) (toAttrib->c3Max - toAttrib->c3Min)); +} + +// TODO: Use PrintGLString, CechckGlError, and PrintEGLConfiguration +// from libglTest +static void printGLString(const char *name, GLenum s) +{ + const char *v = (const char *) glGetString(s); + + if (v == NULL) { + testPrintI("GL %s unknown", name); + } else { + testPrintI("GL %s = %s", name, v); + } +} + +static void checkEglError(const char* op, EGLBoolean returnVal) +{ + if (returnVal != EGL_TRUE) { + testPrintE("%s() returned %d", op, returnVal); + } + + for (EGLint error = eglGetError(); error != EGL_SUCCESS; error + = eglGetError()) { + testPrintE("after %s() eglError %s (0x%x)", + op, EGLUtils::strerror(error), error); + } +} + +static void checkGlError(const char* op) +{ + for (GLint error = glGetError(); error; error + = glGetError()) { + testPrintE("after %s() glError (0x%x)", op, error); + } +} + +static void printEGLConfiguration(EGLDisplay dpy, EGLConfig config) +{ + +#define X(VAL) {VAL, #VAL} + struct {EGLint attribute; const char* name;} names[] = { + X(EGL_BUFFER_SIZE), + X(EGL_ALPHA_SIZE), + X(EGL_BLUE_SIZE), + X(EGL_GREEN_SIZE), + X(EGL_RED_SIZE), + X(EGL_DEPTH_SIZE), + X(EGL_STENCIL_SIZE), + X(EGL_CONFIG_CAVEAT), + X(EGL_CONFIG_ID), + X(EGL_LEVEL), + X(EGL_MAX_PBUFFER_HEIGHT), + X(EGL_MAX_PBUFFER_PIXELS), + X(EGL_MAX_PBUFFER_WIDTH), + X(EGL_NATIVE_RENDERABLE), + X(EGL_NATIVE_VISUAL_ID), + X(EGL_NATIVE_VISUAL_TYPE), + X(EGL_SAMPLES), + X(EGL_SAMPLE_BUFFERS), + X(EGL_SURFACE_TYPE), + X(EGL_TRANSPARENT_TYPE), + X(EGL_TRANSPARENT_RED_VALUE), + X(EGL_TRANSPARENT_GREEN_VALUE), + X(EGL_TRANSPARENT_BLUE_VALUE), + X(EGL_BIND_TO_TEXTURE_RGB), + X(EGL_BIND_TO_TEXTURE_RGBA), + X(EGL_MIN_SWAP_INTERVAL), + X(EGL_MAX_SWAP_INTERVAL), + X(EGL_LUMINANCE_SIZE), + X(EGL_ALPHA_MASK_SIZE), + X(EGL_COLOR_BUFFER_TYPE), + X(EGL_RENDERABLE_TYPE), + X(EGL_CONFORMANT), + }; +#undef X + + for (size_t j = 0; j < sizeof(names) / sizeof(names[0]); j++) { + EGLint value = -1; + EGLint returnVal = eglGetConfigAttrib(dpy, config, names[j].attribute, + &value); + EGLint error = eglGetError(); + if (returnVal && error == EGL_SUCCESS) { + testPrintI(" %s: %d (%#x)", names[j].name, value, value); + } + } + testPrintI(""); +} diff --git a/opengl/tests/hwc/hwcTestLib.h b/opengl/tests/hwc/hwcTestLib.h new file mode 100644 index 0000000..e19e163 --- /dev/null +++ b/opengl/tests/hwc/hwcTestLib.h @@ -0,0 +1,133 @@ +/* + * 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 Test Library Header + */ + +#include <sstream> +#include <string> + +#include <EGL/egl.h> +#include <EGL/eglext.h> +#include <GLES2/gl2.h> +#include <GLES2/gl2ext.h> + +#include <ui/FramebufferNativeWindow.h> +#include <ui/GraphicBuffer.h> +#include <ui/EGLUtils.h> + +#include <utils/Log.h> +#include <testUtil.h> + +#include <hardware/hwcomposer.h> + +// Characteristics of known graphic formats +const struct hwcTestGraphicFormat { + uint32_t format; + const char *desc; + uint32_t wMod, hMod; // Width/height mod this value must equal zero +} hwcTestGraphicFormat[] = { + {HAL_PIXEL_FORMAT_RGBA_8888, "RGBA8888", 1, 1}, + {HAL_PIXEL_FORMAT_RGBX_8888, "RGBX8888", 1, 1}, + {HAL_PIXEL_FORMAT_RGB_888, "RGB888", 1, 1}, + {HAL_PIXEL_FORMAT_RGB_565, "RGB565", 1, 1}, + {HAL_PIXEL_FORMAT_BGRA_8888, "BGRA8888", 1, 1}, + {HAL_PIXEL_FORMAT_RGBA_5551, "RGBA5551", 1, 1}, + {HAL_PIXEL_FORMAT_RGBA_4444, "RGBA4444", 1, 1}, + {HAL_PIXEL_FORMAT_YV12, "YV12", 2, 2}, +}; + +// Represent RGB color as fraction of color components. +// Each of the color components are expected in the range [0.0, 1.0] +class ColorFract { + public: + ColorFract(): _c1(0.0), _c2(0.0), _c3(0.0) {}; + ColorFract(float c1, float c2, float c3): _c1(c1), _c2(c2), _c3(c3) {}; + float c1(void) const { return _c1; } + float c2(void) const { return _c2; } + float c3(void) const { return _c3; } + + operator std::string(); + + private: + float _c1; + float _c2; + float _c3; +}; + +// Represent RGB color as fraction of color components. +// Each of the color components are expected in the range [0.0, 1.0] +class ColorRGB { + public: + ColorRGB(): _r(0.0), _g(0.0), _b(0.0) {}; + ColorRGB(float f): _r(f), _g(f), _b(f) {}; // Gray + ColorRGB(float r, float g, float b): _r(r), _g(g), _b(b) {}; + float r(void) const { return _r; } + float g(void) const { return _g; } + float b(void) const { return _b; } + + private: + float _r; + float _g; + float _b; +}; + +// Dimension - width and height of a rectanguler area +class HwcTestDim { + public: + HwcTestDim(): _w(0), _h(0) {}; + HwcTestDim(uint32_t w, uint32_t h) : _w(w), _h(h) {} + uint32_t width(void) const { return _w; } + uint32_t height(void) const { return _h; } + void setWidth(uint32_t w) { _w = w; } + void setHeight(uint32_t h) { _h = h; } + + operator std::string(); + + private: + uint32_t _w; + uint32_t _h; +}; + +// Function Prototypes +void hwcTestInitDisplay(bool verbose, EGLDisplay *dpy, EGLSurface *surface, + EGLint *width, EGLint *height); +void hwcTestOpenHwc(hwc_composer_device_t **hwcDevicePtr); +const struct hwcTestGraphicFormat *hwcTestGraphicFormatLookup(const char *desc); +const char *hwcTestGraphicFormat2str(uint32_t format); +std::string hwcTestRect2str(const struct hwc_rect& rect); + +hwc_layer_list_t *hwcTestCreateLayerList(size_t numLayers); +void hwcTestFreeLayerList(hwc_layer_list_t *list); +void hwcTestDisplayList(hwc_layer_list_t *list); +void hwcTestDisplayListPrepareModifiable(hwc_layer_list_t *list); +void hwcTestDisplayListHandles(hwc_layer_list_t *list); + +uint32_t hwcTestColor2Pixel(uint32_t format, ColorFract color, float alpha); +void hwcTestColorConvert(uint32_t fromFormat, uint32_t toFormat, + ColorFract& color); +void hwcTestSetPixel(android::GraphicBuffer *gBuf, unsigned char *buf, + uint32_t x, uint32_t y, uint32_t pixel); +void hwcTestFillColor(android::GraphicBuffer *gBuf, ColorFract color, + float alpha); +void hwcTestFillColorHBlend(android::GraphicBuffer *gBuf, + uint32_t colorFormat, + ColorFract startColor, ColorFract endColor); +ColorFract hwcTestParseColor(std::istringstream& in, bool& error); +struct hwc_rect hwcTestParseHwcRect(std::istringstream& in, bool& error); +HwcTestDim hwcTestParseDim(std::istringstream& in, bool& error); diff --git a/opengl/tests/include/glTestLib.h b/opengl/tests/include/glTestLib.h new file mode 100644 index 0000000..06fbf5d --- /dev/null +++ b/opengl/tests/include/glTestLib.h @@ -0,0 +1,34 @@ +/* + * 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. + * + */ + +/* + * Graphics Test Library Header + */ + +#include <EGL/egl.h> +#include <EGL/eglext.h> +#include <GLES2/gl2.h> +#include <GLES2/gl2ext.h> + +//#include <ui/FramebufferNativeWindow.h> +//#include <ui/GraphicBuffer.h> +#include <ui/EGLUtils.h> + +void glTestPrintGLString(const char *name, GLenum s); +void glTestCheckEglError(const char* op, EGLBoolean returnVal = EGL_TRUE); +void glTestCheckGlError(const char* op); +void glTestPrintEGLConfiguration(EGLDisplay dpy, EGLConfig config); diff --git a/opengl/tests/lib/Android.mk b/opengl/tests/lib/Android.mk new file mode 100644 index 0000000..7542ac4 --- /dev/null +++ b/opengl/tests/lib/Android.mk @@ -0,0 +1,32 @@ +# Copyright (C) 2010 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. + +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_MODULE_TAGS := tests +LOCAL_MODULE:= libglTest +LOCAL_SRC_FILES:= glTestLib.cpp +LOCAL_C_INCLUDES += system/extras/tests/include \ + bionic \ + bionic/libstdc++/include \ + external/stlport/stlport \ + frameworks/base/opengl/tests/include \ + +LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES + +LOCAL_SHARED_LIBRARIES += libcutils libutils libstlport +LOCAL_PRELINK_MODULE := false + +include $(BUILD_STATIC_LIBRARY) diff --git a/opengl/tests/lib/glTestLib.cpp b/opengl/tests/lib/glTestLib.cpp new file mode 100644 index 0000000..052cbd7 --- /dev/null +++ b/opengl/tests/lib/glTestLib.cpp @@ -0,0 +1,119 @@ +/* + * 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. + * + */ + +/* + * Graphics Test Library + */ + +#include <glTestLib.h> + +#include <EGL/egl.h> +#include <EGL/eglext.h> +#include <GLES2/gl2.h> +#include <GLES2/gl2ext.h> + +#include <ui/EGLUtils.h> + +#include <utils/Log.h> +#include <testUtil.h> + +using namespace std; +using namespace android; + +void glTestPrintGLString(const char *name, GLenum s) +{ + const char *v = (const char *) glGetString(s); + + if (v == NULL) { + testPrintI("GL %s unknown", name); + } else { + testPrintI("GL %s = %s", name, v); + } +} + +void glTestCheckEglError(const char* op, EGLBoolean returnVal) +{ + if (returnVal != EGL_TRUE) { + testPrintE("%s() returned %d", op, returnVal); + } + + for (EGLint error = eglGetError(); error != EGL_SUCCESS; error + = eglGetError()) { + testPrintE("after %s() eglError %s (0x%x)", + op, EGLUtils::strerror(error), error); + } +} + +void glTestCheckGlError(const char* op) +{ + for (GLint error = glGetError(); error; error + = glGetError()) { + testPrintE("after %s() glError (0x%x)", op, error); + } +} + +void glTestPrintEGLConfiguration(EGLDisplay dpy, EGLConfig config) +{ + +#define X(VAL) {VAL, #VAL} + struct {EGLint attribute; const char* name;} names[] = { + X(EGL_BUFFER_SIZE), + X(EGL_ALPHA_SIZE), + X(EGL_BLUE_SIZE), + X(EGL_GREEN_SIZE), + X(EGL_RED_SIZE), + X(EGL_DEPTH_SIZE), + X(EGL_STENCIL_SIZE), + X(EGL_CONFIG_CAVEAT), + X(EGL_CONFIG_ID), + X(EGL_LEVEL), + X(EGL_MAX_PBUFFER_HEIGHT), + X(EGL_MAX_PBUFFER_PIXELS), + X(EGL_MAX_PBUFFER_WIDTH), + X(EGL_NATIVE_RENDERABLE), + X(EGL_NATIVE_VISUAL_ID), + X(EGL_NATIVE_VISUAL_TYPE), + X(EGL_SAMPLES), + X(EGL_SAMPLE_BUFFERS), + X(EGL_SURFACE_TYPE), + X(EGL_TRANSPARENT_TYPE), + X(EGL_TRANSPARENT_RED_VALUE), + X(EGL_TRANSPARENT_GREEN_VALUE), + X(EGL_TRANSPARENT_BLUE_VALUE), + X(EGL_BIND_TO_TEXTURE_RGB), + X(EGL_BIND_TO_TEXTURE_RGBA), + X(EGL_MIN_SWAP_INTERVAL), + X(EGL_MAX_SWAP_INTERVAL), + X(EGL_LUMINANCE_SIZE), + X(EGL_ALPHA_MASK_SIZE), + X(EGL_COLOR_BUFFER_TYPE), + X(EGL_RENDERABLE_TYPE), + X(EGL_CONFORMANT), + }; +#undef X + + for (size_t j = 0; j < sizeof(names) / sizeof(names[0]); j++) { + EGLint value = -1; + EGLint returnVal = eglGetConfigAttrib(dpy, config, names[j].attribute, + &value); + EGLint error = eglGetError(); + if (returnVal && error == EGL_SUCCESS) { + testPrintI(" %s: %d (%#x)", names[j].name, value, value); + } + } + testPrintI(""); +} |