From ec0da1a5ffc0c856efea16e6a05f2ce9e7c82a94 Mon Sep 17 00:00:00 2001 From: Louis Huemiller Date: Wed, 5 Jan 2011 18:53:47 -0800 Subject: Hardware Composer new and refactored test cases Change-Id: Iabf46fc5d75891f917e06a257470a0e3f2bd3c95 --- opengl/tests/hwc/Android.mk | 103 ++- opengl/tests/hwc/hwcColorEquiv.cpp | 436 +++++++++++++ opengl/tests/hwc/hwcRects.cpp | 575 ++++++++++++++++ opengl/tests/hwc/hwcStress.cpp | 645 ++++++++++++++++++ opengl/tests/hwc/hwcTestLib.cpp | 995 ++++++++++++++++++++++++++++ opengl/tests/hwc/hwcTestLib.h | 133 ++++ opengl/tests/hwc/hwc_stress.cpp | 1262 ------------------------------------ opengl/tests/include/glTestLib.h | 34 + opengl/tests/lib/Android.mk | 32 + opengl/tests/lib/glTestLib.cpp | 119 ++++ 10 files changed, 3070 insertions(+), 1264 deletions(-) create mode 100644 opengl/tests/hwc/hwcColorEquiv.cpp create mode 100644 opengl/tests/hwc/hwcRects.cpp create mode 100644 opengl/tests/hwc/hwcStress.cpp create mode 100644 opengl/tests/hwc/hwcTestLib.cpp create mode 100644 opengl/tests/hwc/hwcTestLib.h delete mode 100644 opengl/tests/hwc/hwc_stress.cpp create mode 100644 opengl/tests/include/glTestLib.h create mode 100644 opengl/tests/lib/Android.mk create mode 100644 opengl/tests/lib/glTestLib.cpp (limited to 'opengl/tests') 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#define LOG_TAG "hwcColorEquivTest" +#include +#include + +#include + +#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 , 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 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 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#define LOG_TAG "hwcColorEquivTest" +#include +#include + +#include + +#include +#include + +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 texture; +}; + +// Globals +list 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::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/hwcStress.cpp b/opengl/tests/hwc/hwcStress.cpp new file mode 100644 index 0000000..1cefb4b --- /dev/null +++ b/opengl/tests/hwc/hwcStress.cpp @@ -0,0 +1,645 @@ +/* + * 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. + * + */ + +/* + * Hardware Composer stress test + * + * Performs a pseudo-random (prandom) sequence of operations to the + * Hardware Composer (HWC), for a specified number of passes or for + * a specified period of time. By default the period of time is FLT_MAX, + * so that the number of passes will take precedence. + * + * The passes are grouped together, where (pass / passesPerGroup) specifies + * which group a particular pass is in. This causes every passesPerGroup + * worth of sequential passes to be within the same group. Computationally + * intensive operations are performed just once at the beginning of a group + * of passes and then used by all the passes in that group. This is done + * so as to increase both the average and peak rate of graphic operations, + * by moving computationally intensive operations to the beginning of a group. + * In particular, at the start of each group of passes a set of + * graphic buffers are created, then used by the first and remaining + * passes of that group of passes. + * + * The per-group initialization of the graphic buffers is performed + * by a function called initFrames. This function creates an array + * of smart pointers to the graphic buffers, in the form of a vector + * of vectors. The array is accessed in row major order, so each + * row is a vector of smart pointers. All the pointers of a single + * row point to graphic buffers which use the same pixel format and + * have the same dimension, although it is likely that each one is + * filled with a different color. This is done so that after doing + * the first HWC prepare then set call, subsequent set calls can + * be made with each of the layer handles changed to a different + * graphic buffer within the same row. Since the graphic buffers + * in a particular row have the same pixel format and dimension, + * additional HWC set calls can be made, without having to perform + * an HWC prepare call. + * + * This test supports the following command-line options: + * + * -v Verbose + * -s num Starting pass + * -e num Ending pass + * -p num Execute the single pass specified by num + * -n num Number of set operations to perform after each prepare operation + * -t float Maximum time in seconds to execute the test + * -d float Delay in seconds performed after each set operation + * -D float Delay in seconds performed after the last pass is executed + * + * Typically the test is executed for a large range of passes. By default + * passes 0 through 99999 (100,000 passes) are executed. Although this test + * does not validate the generated image, at times it is useful to reexecute + * a particular pass and leave the displayed image on the screen for an + * extended period of time. This can be done either by setting the -s + * and -e options to the desired pass, along with a large value for -D. + * This can also be done via the -p option, again with a large value for + * the -D options. + * + * So far this test only contains code to create graphic buffers with + * a continuous solid color. Although this test is unable to validate the + * image produced, any image that contains other than rectangles of a solid + * color are incorrect. Note that the rectangles may use a transparent + * color and have a blending operation that causes the color in overlapping + * rectangles to be mixed. In such cases the overlapping portions may have + * a different color from the rest of the rectangle. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#define LOG_TAG "hwcStressTest" +#include +#include + +#include + +#include +#include + +using namespace std; +using namespace android; + +const float maxSizeRatio = 1.3; // Graphic buffers can be upto this munch + // larger than the default screen size +const unsigned int passesPerGroup = 10; // A group of passes all use the same + // graphic buffers + +// Ratios at which rare and frequent conditions should be produced +const float rareRatio = 0.1; +const float freqRatio = 0.9; + +// Defaults for command-line options +const bool defaultVerbose = false; +const unsigned int defaultStartPass = 0; +const unsigned int defaultEndPass = 99999; +const unsigned int defaultPerPassNumSet = 10; +const float defaultPerSetDelay = 0.0; // Default delay after each set + // operation. Default delay of + // zero used so as to perform the + // the set operations as quickly + // as possible. +const float defaultEndDelay = 2.0; // Default delay between completion of + // final pass and restart of framework +const float defaultDuration = FLT_MAX; // A fairly long time, so that + // range of passes will have + // precedence + +// Command-line option settings +static bool verbose = defaultVerbose; +static unsigned int startPass = defaultStartPass; +static unsigned int endPass = defaultEndPass; +static unsigned int numSet = defaultPerPassNumSet; +static float perSetDelay = defaultPerSetDelay; +static float endDelay = defaultEndDelay; +static float duration = defaultDuration; + +// Command-line mutual exclusion detection flags. +// Corresponding flag set true once an option is used. +bool eFlag, sFlag, pFlag; + +#define MAXSTR 100 +#define MAXCMD 200 +#define BITSPERBYTE 8 // TODO: Obtain from , once + // it has been added + +#define CMD_STOP_FRAMEWORK "stop 2>&1" +#define CMD_START_FRAMEWORK "start 2>&1" + +#define NUMA(a) (sizeof(a) / sizeof(a [0])) +#define MEMCLR(addr, size) do { \ + memset((addr), 0, (size)); \ + } while (0) + +// File scope constants +const unsigned int blendingOps[] = { + HWC_BLENDING_NONE, + HWC_BLENDING_PREMULT, + HWC_BLENDING_COVERAGE, +}; +const unsigned int layerFlags[] = { + HWC_SKIP_LAYER, +}; +const vector vecLayerFlags(layerFlags, + layerFlags + NUMA(layerFlags)); + +const unsigned int transformFlags[] = { + HWC_TRANSFORM_FLIP_H, + HWC_TRANSFORM_FLIP_V, + HWC_TRANSFORM_ROT_90, + // ROT_180 & ROT_270 intentionally not listed, because they + // they are formed from combinations of the flags already listed. +}; +const vector vecTransformFlags(transformFlags, + transformFlags + NUMA(transformFlags)); + +// File scope 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; +static vector > > frames; + +// File scope prototypes +void init(void); +void initFrames(unsigned int seed); +template vector vectorRandSelect(const vector& vec, size_t num); +template T vectorOr(const vector& vec); + +/* + * Main + * + * Performs the following high-level sequence of operations: + * + * 1. Command-line parsing + * + * 2. Initialization + * + * 3. For each pass: + * + * a. If pass is first pass or in a different group from the + * previous pass, initialize the array of graphic buffers. + * + * b. Create a HWC list with room to specify a prandomly + * selected number of layers. + * + * c. Select a subset of the rows from the graphic buffer array, + * such that there is a unique row to be used for each + * of the layers in the HWC list. + * + * d. Prandomly fill in the HWC list with handles + * selected from any of the columns of the selected row. + * + * e. Pass the populated list to the HWC prepare call. + * + * f. Pass the populated list to the HWC set call. + * + * g. If additional set calls are to be made, then for each + * additional set call, select a new set of handles and + * perform the set call. + */ +int +main(int argc, char *argv[]) +{ + int rv, opt; + char *chptr; + unsigned int pass; + char cmd[MAXCMD]; + struct timeval startTime, currentTime, delta; + + testSetLogCatTag(LOG_TAG); + + // Parse command line arguments + while ((opt = getopt(argc, argv, "vp:d:D:n:s:e:t:?h")) != -1) { + switch (opt) { + case 'd': // Delay after each set operation + perSetDelay = strtod(optarg, &chptr); + if ((*chptr != '\0') || (perSetDelay < 0.0)) { + testPrintE("Invalid command-line specified per pass delay of: " + "%s", optarg); + exit(1); + } + break; + + 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(2); + } + break; + + case 't': // Duration + duration = strtod(optarg, &chptr); + if ((*chptr != '\0') || (duration < 0.0)) { + testPrintE("Invalid command-line specified duration of: %s", + optarg); + exit(3); + } + break; + + case 'n': // Num set operations per pass + numSet = strtoul(optarg, &chptr, 10); + if (*chptr != '\0') { + testPrintE("Invalid command-line specified num set per pass " + "of: %s", optarg); + exit(4); + } + break; + + case 's': // Starting Pass + sFlag = true; + if (pFlag) { + testPrintE("Invalid combination of command-line options."); + testPrintE(" The -p option is mutually exclusive from the"); + testPrintE(" -s and -e options."); + exit(5); + } + startPass = strtoul(optarg, &chptr, 10); + if (*chptr != '\0') { + testPrintE("Invalid command-line specified starting pass " + "of: %s", optarg); + exit(6); + } + break; + + case 'e': // Ending Pass + eFlag = true; + if (pFlag) { + testPrintE("Invalid combination of command-line options."); + testPrintE(" The -p option is mutually exclusive from the"); + testPrintE(" -s and -e options."); + exit(7); + } + endPass = strtoul(optarg, &chptr, 10); + if (*chptr != '\0') { + testPrintE("Invalid command-line specified ending pass " + "of: %s", optarg); + exit(8); + } + break; + + case 'p': // Run a single specified pass + pFlag = true; + if (sFlag || eFlag) { + testPrintE("Invalid combination of command-line options."); + testPrintE(" The -p option is mutually exclusive from the"); + testPrintE(" -s and -e options."); + exit(9); + } + startPass = endPass = strtoul(optarg, &chptr, 10); + if (*chptr != '\0') { + testPrintE("Invalid command-line specified pass of: %s", + optarg); + exit(10); + } + break; + + case 'v': // Verbose + verbose = true; + break; + + case 'h': // Help + case '?': + default: + testPrintE(" %s [options]", basename(argv[0])); + testPrintE(" options:"); + testPrintE(" -p Execute specified pass"); + testPrintE(" -s Starting pass"); + testPrintE(" -e Ending pass"); + testPrintE(" -t Duration"); + testPrintE(" -d Delay after each set operation"); + testPrintE(" -D End of test delay"); + testPrintE(" -n Num set operations per pass"); + testPrintE(" -v Verbose"); + exit(((optopt == 0) || (optopt == '?')) ? 0 : 11); + } + } + if (endPass < startPass) { + testPrintE("Unexpected ending pass before starting pass"); + testPrintE(" startPass: %u endPass: %u", startPass, endPass); + exit(12); + } + if (argc != optind) { + testPrintE("Unexpected command-line postional argument"); + testPrintE(" %s [-s start_pass] [-e end_pass] [-t duration]", + basename(argv[0])); + exit(13); + } + testPrintI("duration: %g", duration); + testPrintI("startPass: %u", startPass); + testPrintI("endPass: %u", endPass); + testPrintI("numSet: %u", numSet); + + // 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(14); + } + testExecCmd(cmd); + testDelay(1.0); // TODO - need means to query whether asyncronous stop + // framework operation has completed. For now, just wait + // a long time. + + init(); + + // For each pass + gettimeofday(&startTime, NULL); + for (pass = startPass; pass <= endPass; pass++) { + // Stop if duration of work has already been performed + gettimeofday(¤tTime, NULL); + delta = tvDelta(&startTime, ¤tTime); + if (tv2double(&delta) > duration) { break; } + + // Regenerate a new set of test frames when this pass is + // either the first pass or is in a different group then + // the previous pass. A group of passes are passes that + // all have the same quotient when their pass number is + // divided by passesPerGroup. + if ((pass == startPass) + || ((pass / passesPerGroup) != ((pass - 1) / passesPerGroup))) { + initFrames(pass / passesPerGroup); + } + + testPrintI("==== Starting pass: %u", pass); + + // Cause deterministic sequence of prandom numbers to be + // generated for this pass. + srand48(pass); + + hwc_layer_list_t *list; + list = hwcTestCreateLayerList(testRandMod(frames.size()) + 1); + if (list == NULL) { + testPrintE("hwcTestCreateLayerList failed"); + exit(20); + } + + // Prandomly select a subset of frames to be used by this pass. + vector > > selectedFrames; + selectedFrames = vectorRandSelect(frames, list->numHwLayers); + + // Any transform tends to create a layer that the hardware + // composer is unable to support and thus has to leave for + // SurfaceFlinger. Place heavy bias on specifying no transforms. + bool noTransform = testRandFract() > rareRatio; + + for (unsigned int n1 = 0; n1 < list->numHwLayers; n1++) { + unsigned int idx = testRandMod(selectedFrames[n1].size()); + sp gBuf = selectedFrames[n1][idx]; + hwc_layer_t *layer = &list->hwLayers[n1]; + layer->handle = gBuf->handle; + + layer->blending = blendingOps[testRandMod(NUMA(blendingOps))]; + layer->flags = (testRandFract() > rareRatio) ? 0 + : vectorOr(vectorRandSelect(vecLayerFlags, + testRandMod(vecLayerFlags.size() + 1))); + layer->transform = (noTransform || testRandFract() > rareRatio) ? 0 + : vectorOr(vectorRandSelect(vecTransformFlags, + testRandMod(vecTransformFlags.size() + 1))); + layer->sourceCrop.left = testRandMod(gBuf->getWidth()); + layer->sourceCrop.top = testRandMod(gBuf->getHeight()); + layer->sourceCrop.right = layer->sourceCrop.left + + testRandMod(gBuf->getWidth() - layer->sourceCrop.left) + 1; + layer->sourceCrop.bottom = layer->sourceCrop.top + + testRandMod(gBuf->getHeight() - layer->sourceCrop.top) + 1; + layer->displayFrame.left = testRandMod(width); + layer->displayFrame.top = testRandMod(height); + layer->displayFrame.right = layer->displayFrame.left + + testRandMod(width - layer->displayFrame.left) + 1; + layer->displayFrame.bottom = layer->displayFrame.top + + testRandMod(height - layer->displayFrame.top) + 1; + + // Increase the frequency that a scale factor of 1.0 from + // the sourceCrop to displayFrame occurs. This is the + // most common scale factor used by applications and would + // be rarely produced by this stress test without this + // logic. + if (testRandFract() <= freqRatio) { + // Only change to scale factor to 1.0 if both the + // width and height will fit. + int sourceWidth = layer->sourceCrop.right + - layer->sourceCrop.left; + int sourceHeight = layer->sourceCrop.bottom + - layer->sourceCrop.top; + if (((layer->displayFrame.left + sourceWidth) <= width) + && ((layer->displayFrame.top + sourceHeight) <= height)) { + layer->displayFrame.right = layer->displayFrame.left + + sourceWidth; + layer->displayFrame.bottom = layer->displayFrame.top + + sourceHeight; + } + } + + 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:"); } + for (unsigned int n1 = 0; n1 < numSet; n1++) { + if (verbose) { hwcTestDisplayListHandles(list); } + hwcDevice->set(hwcDevice, dpy, surface, list); + + // Prandomly select a new set of handles + for (unsigned int n1 = 0; n1 < list->numHwLayers; n1++) { + unsigned int idx = testRandMod(selectedFrames[n1].size()); + sp gBuf = selectedFrames[n1][idx]; + hwc_layer_t *layer = &list->hwLayers[n1]; + layer->handle = (native_handle_t *) gBuf->handle; + } + + testDelay(perSetDelay); + } + + hwcTestFreeLayerList(list); + testPrintI("==== Completed pass: %u", pass); + } + + 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(21); + } + testExecCmd(cmd); + + testPrintI("Successfully completed %u passes", pass - startPass); + + return 0; +} + +void init(void) +{ + 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. + + hwcTestInitDisplay(verbose, &dpy, &surface, &width, &height); + + hwcTestOpenHwc(&hwcDevice); +} + +/* + * Initialize Frames + * + * Creates an array of graphic buffers, within the global variable + * named frames. The graphic buffers are contained within a vector of + * vectors. All the graphic buffers in a particular row are of the same + * format and dimension. Each graphic buffer is uniformly filled with a + * prandomly selected color. It is likely that each buffer, even + * in the same row, will be filled with a unique color. + */ +void initFrames(unsigned int seed) +{ + int rv; + const size_t maxRows = 5; + const size_t minCols = 2; // Need at least double buffering + const size_t maxCols = 4; // One more than triple buffering + + if (verbose) { testPrintI("initFrames seed: %u", seed); } + srand48(seed); + size_t rows = testRandMod(maxRows) + 1; + + frames.clear(); + frames.resize(rows); + + 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(hwcTestGraphicFormat)); + const struct hwcTestGraphicFormat *formatPtr + = &hwcTestGraphicFormat[formatIdx]; + int format = formatPtr->format; + + // Pick width and height, which must be >= 1 and the size + // mod the wMod/hMod value must be equal to 0. + size_t w = (width * maxSizeRatio) * testRandFract(); + size_t h = (height * maxSizeRatio) * testRandFract(); + w = max(1u, w); + h = max(1u, h); + if ((w % formatPtr->wMod) != 0) { + w += formatPtr->wMod - (w % formatPtr->wMod); + } + if ((h % formatPtr->hMod) != 0) { + h += formatPtr->hMod - (h % formatPtr->hMod); + } + if (verbose) { + testPrintI(" frame %u width: %u height: %u format: %u %s", + 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++) { + 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, hwcTestGraphicFormat2str(format)); + exit(80); + } + + hwcTestFillColor(frames[row][col].get(), color, alpha); + if (verbose) { + testPrintI(" buf: %p handle: %p color: %s alpha: %f", + frames[row][col].get(), frames[row][col]->handle, + string(color).c_str(), alpha); + } + } + } +} + +/* + * Vector Random Select + * + * Prandomly selects and returns num elements from vec. + */ +template +vector vectorRandSelect(const vector& vec, size_t num) +{ + vector rv = vec; + + while (rv.size() > num) { + rv.erase(rv.begin() + testRandMod(rv.size())); + } + + return rv; +} + +/* + * Vector Or + * + * Or's togethen the values of each element of vec and returns the result. + */ +template +T vectorOr(const vector& vec) +{ + T rv = 0; + + for (size_t n1 = 0; n1 < vec.size(); n1++) { + rv |= vec[n1]; + } + + return rv; +} 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 +#include + +#include // For ntohl() and htonl() + +#include + +// 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 , 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(""); + *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 +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +// 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/hwc/hwc_stress.cpp b/opengl/tests/hwc/hwc_stress.cpp deleted file mode 100644 index 580eb83..0000000 --- a/opengl/tests/hwc/hwc_stress.cpp +++ /dev/null @@ -1,1262 +0,0 @@ -/* - * 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. - * - */ - -/* - * Hardware Composer stress test - * - * Performs a pseudo-random (prandom) sequence of operations to the - * Hardware Composer (HWC), for a specified number of passes or for - * a specified period of time. By default the period of time is FLT_MAX, - * so that the number of passes will take precedence. - * - * The passes are grouped together, where (pass / passesPerGroup) specifies - * which group a particular pass is in. This causes every passesPerGroup - * worth of sequential passes to be within the same group. Computationally - * intensive operations are performed just once at the beginning of a group - * of passes and then used by all the passes in that group. This is done - * so as to increase both the average and peak rate of graphic operations, - * by moving computationally intensive operations to the beginning of a group. - * In particular, at the start of each group of passes a set of - * graphic buffers are created, then used by the first and remaining - * passes of that group of passes. - * - * The per-group initialization of the graphic buffers is performed - * by a function called initFrames. This function creates an array - * of smart pointers to the graphic buffers, in the form of a vector - * of vectors. The array is accessed in row major order, so each - * row is a vector of smart pointers. All the pointers of a single - * row point to graphic buffers which use the same pixel format and - * have the same dimension, although it is likely that each one is - * filled with a different color. This is done so that after doing - * the first HWC prepare then set call, subsequent set calls can - * be made with each of the layer handles changed to a different - * graphic buffer within the same row. Since the graphic buffers - * in a particular row have the same pixel format and dimension, - * additional HWC set calls can be made, without having to perform - * an HWC prepare call. - * - * This test supports the following command-line options: - * - * -v Verbose - * -s num Starting pass - * -e num Ending pass - * -p num Execute the single pass specified by num - * -n num Number of set operations to perform after each prepare operation - * -t float Maximum time in seconds to execute the test - * -d float Delay in seconds performed after each set operation - * -D float Delay in seconds performed after the last pass is executed - * - * Typically the test is executed for a large range of passes. By default - * passes 0 through 99999 (100,000 passes) are executed. Although this test - * does not validate the generated image, at times it is useful to reexecute - * a particular pass and leave the displayed image on the screen for an - * extended period of time. This can be done either by setting the -s - * and -e options to the desired pass, along with a large value for -D. - * This can also be done via the -p option, again with a large value for - * the -D options. - * - * So far this test only contains code to create graphic buffers with - * a continuous solid color. Although this test is unable to validate the - * image produced, any image that contains other than rectangles of a solid - * color are incorrect. Note that the rectangles may use a transparent - * color and have a blending operation that causes the color in overlapping - * rectangles to be mixed. In such cases the overlapping portions may have - * a different color from the rest of the rectangle. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include // For ntohl() and htonl() - -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include - -#define LOG_TAG "hwcStressTest" -#include -#include - -#include - -using namespace std; -using namespace android; - -const float maxSizeRatio = 1.3; // Graphic buffers can be upto this munch - // larger than the default screen size -const unsigned int passesPerGroup = 10; // A group of passes all use the same - // graphic buffers - -// Ratios at which rare and frequent conditions should be produced -const float rareRatio = 0.1; -const float freqRatio = 0.9; - -// Defaults for command-line options -const bool defaultVerbose = false; -const unsigned int defaultStartPass = 0; -const unsigned int defaultEndPass = 99999; -const unsigned int defaultPerPassNumSet = 10; -const float defaultPerSetDelay = 0.0; // Default delay after each set - // operation. Default delay of - // zero used so as to perform the - // the set operations as quickly - // as possible. -const float defaultEndDelay = 2.0; // Default delay between completion of - // final pass and restart of framework -const float defaultDuration = FLT_MAX; // A fairly long time, so that - // range of passes will have - // precedence - -// Command-line option settings -static bool verbose = defaultVerbose; -static unsigned int startPass = defaultStartPass; -static unsigned int endPass = defaultEndPass; -static unsigned int numSet = defaultPerPassNumSet; -static float perSetDelay = defaultPerSetDelay; -static float endDelay = defaultEndDelay; -static float duration = defaultDuration; - -// Command-line mutual exclusion detection flags. -// Corresponding flag set true once an option is used. -bool eFlag, sFlag, pFlag; - -#define MAXSTR 100 -#define MAXCMD 200 -#define BITSPERBYTE 8 // TODO: Obtain from , once - // it has been added - -#define CMD_STOP_FRAMEWORK "stop 2>&1" -#define CMD_START_FRAMEWORK "start 2>&1" - -#define NUMA(a) (sizeof(a) / sizeof(a [0])) -#define MEMCLR(addr, size) do { \ - 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, - HWC_BLENDING_COVERAGE, -}; -const unsigned int layerFlags[] = { - HWC_SKIP_LAYER, -}; -const vector vecLayerFlags(layerFlags, - layerFlags + NUMA(layerFlags)); - -const unsigned int transformFlags[] = { - HWC_TRANSFORM_FLIP_H, - HWC_TRANSFORM_FLIP_V, - HWC_TRANSFORM_ROT_90, - // ROT_180 & ROT_270 intentionally not listed, because they - // they are formed from combinations of the flags already listed. -}; -const vector vecTransformFlags(transformFlags, - transformFlags + NUMA(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 > > frames; -static EGLDisplay dpy; -static EGLContext context; -static EGLSurface surface; -static EGLint width, height; - -// 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 vector vectorRandSelect(const vector& vec, size_t num); -template T vectorOr(const vector& vec); - -/* - * Main - * - * Performs the following high-level sequence of operations: - * - * 1. Command-line parsing - * - * 2. Initialization - * - * 3. For each pass: - * - * a. If pass is first pass or in a different group from the - * previous pass, initialize the array of graphic buffers. - * - * b. Create a HWC list with room to specify a prandomly - * selected number of layers. - * - * c. Select a subset of the rows from the graphic buffer array, - * such that there is a unique row to be used for each - * of the layers in the HWC list. - * - * d. Prandomly fill in the HWC list with handles - * selected from any of the columns of the selected row. - * - * e. Pass the populated list to the HWC prepare call. - * - * f. Pass the populated list to the HWC set call. - * - * g. If additional set calls are to be made, then for each - * additional set call, select a new set of handles and - * perform the set call. - */ -int -main(int argc, char *argv[]) -{ - int rv, opt; - char *chptr; - unsigned int pass; - char cmd[MAXCMD]; - struct timeval startTime, currentTime, delta; - - testSetLogCatTag(LOG_TAG); - - // Parse command line arguments - while ((opt = getopt(argc, argv, "vp:d:D:n:s:e:t:?h")) != -1) { - switch (opt) { - case 'd': // Delay after each set operation - perSetDelay = strtod(optarg, &chptr); - if ((*chptr != '\0') || (perSetDelay < 0.0)) { - testPrintE("Invalid command-line specified per pass delay of: " - "%s", optarg); - exit(1); - } - break; - - 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(2); - } - break; - - case 't': // Duration - duration = strtod(optarg, &chptr); - if ((*chptr != '\0') || (duration < 0.0)) { - testPrintE("Invalid command-line specified duration of: %s", - optarg); - exit(3); - } - break; - - case 'n': // Num set operations per pass - numSet = strtoul(optarg, &chptr, 10); - if (*chptr != '\0') { - testPrintE("Invalid command-line specified num set per pass " - "of: %s", optarg); - exit(4); - } - break; - - case 's': // Starting Pass - sFlag = true; - if (pFlag) { - testPrintE("Invalid combination of command-line options."); - testPrintE(" The -p option is mutually exclusive from the"); - testPrintE(" -s and -e options."); - exit(5); - } - startPass = strtoul(optarg, &chptr, 10); - if (*chptr != '\0') { - testPrintE("Invalid command-line specified starting pass " - "of: %s", optarg); - exit(6); - } - break; - - case 'e': // Ending Pass - eFlag = true; - if (pFlag) { - testPrintE("Invalid combination of command-line options."); - testPrintE(" The -p option is mutually exclusive from the"); - testPrintE(" -s and -e options."); - exit(7); - } - endPass = strtoul(optarg, &chptr, 10); - if (*chptr != '\0') { - testPrintE("Invalid command-line specified ending pass " - "of: %s", optarg); - exit(8); - } - break; - - case 'p': // Run a single specified pass - pFlag = true; - if (sFlag || eFlag) { - testPrintE("Invalid combination of command-line options."); - testPrintE(" The -p option is mutually exclusive from the"); - testPrintE(" -s and -e options."); - exit(9); - } - startPass = endPass = strtoul(optarg, &chptr, 10); - if (*chptr != '\0') { - testPrintE("Invalid command-line specified pass of: %s", - optarg); - exit(10); - } - break; - - case 'v': // Verbose - verbose = true; - break; - - case 'h': // Help - case '?': - default: - testPrintE(" %s [options]", basename(argv[0])); - testPrintE(" options:"); - testPrintE(" -p Execute specified pass"); - testPrintE(" -s Starting pass"); - testPrintE(" -e Ending pass"); - testPrintE(" -t Duration"); - testPrintE(" -d Delay after each set operation"); - testPrintE(" -D End of test delay"); - testPrintE(" -n Num set operations per pass"); - testPrintE(" -v Verbose"); - exit(((optopt == 0) || (optopt == '?')) ? 0 : 11); - } - } - if (endPass < startPass) { - testPrintE("Unexpected ending pass before starting pass"); - testPrintE(" startPass: %u endPass: %u", startPass, endPass); - exit(12); - } - if (argc != optind) { - testPrintE("Unexpected command-line postional argument"); - testPrintE(" %s [-s start_pass] [-e end_pass] [-t duration]", - basename(argv[0])); - exit(13); - } - testPrintI("duration: %g", duration); - testPrintI("startPass: %u", startPass); - testPrintI("endPass: %u", endPass); - testPrintI("numSet: %u", numSet); - - // 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(14); - } - execCmd(cmd); - testDelay(1.0); // TODO - needs means to query whether asyncronous stop - // framework operation has completed. For now, just wait - // a long time. - - init(); - - // For each pass - gettimeofday(&startTime, NULL); - for (pass = startPass; pass <= endPass; pass++) { - // Stop if duration of work has already been performed - gettimeofday(¤tTime, NULL); - delta = tvDelta(&startTime, ¤tTime); - if (tv2double(&delta) > duration) { break; } - - // Regenerate a new set of test frames when this pass is - // either the first pass or is in a different group then - // the previous pass. A group of passes are passes that - // all have the same quotient when their pass number is - // divided by passesPerGroup. - if ((pass == startPass) - || ((pass / passesPerGroup) != ((pass - 1) / passesPerGroup))) { - initFrames(pass / passesPerGroup); - } - - testPrintI("==== Starting pass: %u", pass); - - // Cause deterministic sequence of prandom numbers to be - // generated for this pass. - srand48(pass); - - hwc_layer_list_t *list; - list = createLayerList(testRandMod(frames.size()) + 1); - if (list == NULL) { - testPrintE("createLayerList failed"); - exit(20); - } - - // Prandomly select a subset of frames to be used by this pass. - vector > > selectedFrames; - selectedFrames = vectorRandSelect(frames, list->numHwLayers); - - // Any transform tends to create a layer that the hardware - // composer is unable to support and thus has to leave for - // SurfaceFlinger. Place heavy bias on specifying no transforms. - bool noTransform = testRandFract() > rareRatio; - - for (unsigned int n1 = 0; n1 < list->numHwLayers; n1++) { - unsigned int idx = testRandMod(selectedFrames[n1].size()); - sp gBuf = selectedFrames[n1][idx]; - hwc_layer_t *layer = &list->hwLayers[n1]; - layer->handle = gBuf->handle; - - layer->blending = blendingOps[testRandMod(NUMA(blendingOps))]; - layer->flags = (testRandFract() > rareRatio) ? 0 - : vectorOr(vectorRandSelect(vecLayerFlags, - testRandMod(vecLayerFlags.size() + 1))); - layer->transform = (noTransform || testRandFract() > rareRatio) ? 0 - : vectorOr(vectorRandSelect(vecTransformFlags, - testRandMod(vecTransformFlags.size() + 1))); - layer->sourceCrop.left = testRandMod(gBuf->getWidth()); - layer->sourceCrop.top = testRandMod(gBuf->getHeight()); - layer->sourceCrop.right = layer->sourceCrop.left - + testRandMod(gBuf->getWidth() - layer->sourceCrop.left) + 1; - layer->sourceCrop.bottom = layer->sourceCrop.top - + testRandMod(gBuf->getHeight() - layer->sourceCrop.top) + 1; - layer->displayFrame.left = testRandMod(width); - layer->displayFrame.top = testRandMod(height); - layer->displayFrame.right = layer->displayFrame.left - + testRandMod(width - layer->displayFrame.left) + 1; - layer->displayFrame.bottom = layer->displayFrame.top - + testRandMod(height - layer->displayFrame.top) + 1; - - // Increase the frequency that a scale factor of 1.0 from - // the sourceCrop to displayFrame occurs. This is the - // most common scale factor used by applications and would - // be rarely produced by this stress test without this - // logic. - if (testRandFract() <= freqRatio) { - // Only change to scale factor to 1.0 if both the - // width and height will fit. - int sourceWidth = layer->sourceCrop.right - - layer->sourceCrop.left; - int sourceHeight = layer->sourceCrop.bottom - - layer->sourceCrop.top; - if (((layer->displayFrame.left + sourceWidth) <= width) - && ((layer->displayFrame.top + sourceHeight) <= height)) { - layer->displayFrame.right = layer->displayFrame.left - + sourceWidth; - layer->displayFrame.bottom = layer->displayFrame.top - + sourceHeight; - } - } - - layer->visibleRegionScreen.numRects = 1; - layer->visibleRegionScreen.rects = &layer->displayFrame; - } - - // Perform prepare operation - if (verbose) { testPrintI("Prepare:"); displayList(list); } - hwcDevice->prepare(hwcDevice, list); - if (verbose) { - testPrintI("Post Prepare:"); - displayListPrepareModifiable(list); - } - - // Turn off the geometry changed flag - list->flags &= ~HWC_GEOMETRY_CHANGED; - - // Perform the set operation(s) - if (verbose) {testPrintI("Set:"); } - for (unsigned int n1 = 0; n1 < numSet; n1++) { - if (verbose) {displayListHandles(list); } - hwcDevice->set(hwcDevice, dpy, surface, list); - - // Prandomly select a new set of handles - for (unsigned int n1 = 0; n1 < list->numHwLayers; n1++) { - unsigned int idx = testRandMod(selectedFrames[n1].size()); - sp gBuf = selectedFrames[n1][idx]; - hwc_layer_t *layer = &list->hwLayers[n1]; - layer->handle = (native_handle_t *) gBuf->handle; - } - - testDelay(perSetDelay); - } - - - freeLayerList(list); - testPrintI("==== Completed pass: %u", pass); - } - - 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(21); - } - execCmd(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(""); - 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); - 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"); - - 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(""); -} - -/* - * Initialize Frames - * - * Creates an array of graphic buffers, within the global variable - * named frames. The graphic buffers are contained within a vector of - * vectors. All the graphic buffers in a particular row are of the same - * format and dimension. Each graphic buffer is uniformly filled with a - * prandomly selected color. It is likely that each buffer, even - * in the same row, will be filled with a unique color. - */ -void initFrames(unsigned int seed) -{ - int rv; - const size_t maxRows = 5; - const size_t minCols = 2; // Need at least double buffering - const size_t maxCols = 4; // One more than triple buffering - - if (verbose) { testPrintI("initFrames seed: %u", seed); } - srand48(seed); - size_t rows = testRandMod(maxRows) + 1; - - frames.clear(); - frames.resize(rows); - - 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]; - int format = formatPtr->format; - - // Pick width and height, which must be >= 1 and the size - // mod the wMod/hMod value must be equal to 0. - size_t w = (width * maxSizeRatio) * testRandFract(); - size_t h = (height * maxSizeRatio) * testRandFract(); - w = max(1u, w); - h = max(1u, h); - if ((w % formatPtr->wMod) != 0) { - w += formatPtr->wMod - (w % formatPtr->wMod); - } - if ((h % formatPtr->hMod) != 0) { - h += formatPtr->hMod - (h % formatPtr->hMod); - } - if (verbose) { - testPrintI(" frame %u width: %u height: %u format: %u %s", - row, w, h, format, graphicFormat2str(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(); - - 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)); - exit(80); - } - - fillColor(frames[row][col].get(), color, transp); - if (verbose) { - testPrintI(" buf: %p handle: %p color: <%f, %f, %f> " - "transp: %f", - frames[row][col].get(), frames[row][col]->handle, - color.r(), color.g(), color.b(), transp); - } - } - } -} - -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 - * - * Prandomly selects and returns num elements from vec. - */ -template -vector vectorRandSelect(const vector& vec, size_t num) -{ - vector rv = vec; - - while (rv.size() > num) { - rv.erase(rv.begin() + testRandMod(rv.size())); - } - - return rv; -} - -/* - * Vector Or - * - * Or's togethen the values of each element of vec and returns the result. - */ -template -T vectorOr(const vector& vec) -{ - T rv = 0; - - for (size_t n1 = 0; n1 < vec.size(); n1++) { - rv |= vec[n1]; - } - - return rv; -} 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 +#include +#include +#include + +//#include +//#include +#include + +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 + +#include +#include +#include +#include + +#include + +#include +#include + +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(""); +} -- cgit v1.1