|  | /* | 
|  | * 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 <arpa/inet.h> // For ntohl() and htonl() | 
|  |  | 
|  | #include <cmath> | 
|  | #include <sstream> | 
|  | #include <string> | 
|  |  | 
|  | #include "hwcTestLib.h" | 
|  |  | 
|  | #include "EGLUtils.h" | 
|  |  | 
|  | // Defines | 
|  | #define NUMA(a) (sizeof(a) / sizeof((a)[0])) | 
|  |  | 
|  | // Function Prototypes | 
|  | static void printGLString(const char *name, GLenum s); | 
|  | static void checkEglError(const char* op, EGLBoolean returnVal = EGL_TRUE); | 
|  | static void printEGLConfiguration(EGLDisplay dpy, EGLConfig config); | 
|  |  | 
|  | using namespace std; | 
|  | using namespace android; | 
|  |  | 
|  |  | 
|  | #define BITSPERBYTE            8 // TODO: Obtain from <values.h>, once | 
|  | // it has been added | 
|  |  | 
|  | // Initialize Display | 
|  | void hwcTestInitDisplay(bool verbose, EGLDisplay *dpy, EGLSurface *surface, | 
|  | EGLint *width, EGLint *height) | 
|  | { | 
|  | static EGLContext context; | 
|  |  | 
|  | EGLBoolean returnValue; | 
|  | EGLConfig myConfig = {0}; | 
|  | EGLint contextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; | 
|  | EGLint sConfigAttribs[] = { | 
|  | EGL_SURFACE_TYPE, EGL_WINDOW_BIT, | 
|  | EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, | 
|  | EGL_NONE }; | 
|  | EGLint majorVersion, minorVersion; | 
|  |  | 
|  | checkEglError("<init>"); | 
|  | *dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); | 
|  | checkEglError("eglGetDisplay"); | 
|  | if (*dpy == EGL_NO_DISPLAY) { | 
|  | testPrintE("eglGetDisplay returned EGL_NO_DISPLAY"); | 
|  | exit(70); | 
|  | } | 
|  |  | 
|  | returnValue = eglInitialize(*dpy, &majorVersion, &minorVersion); | 
|  | checkEglError("eglInitialize", returnValue); | 
|  | if (verbose) { | 
|  | testPrintI("EGL version %d.%d", majorVersion, minorVersion); | 
|  | } | 
|  | if (returnValue != EGL_TRUE) { | 
|  | testPrintE("eglInitialize failed"); | 
|  | exit(71); | 
|  | } | 
|  |  | 
|  | // The tests want to stop the framework and play with the hardware | 
|  | // composer, which means it doesn't make sense to use WindowSurface | 
|  | // here.  android_createDisplaySurface() is going away, so just | 
|  | // politely fail here. | 
|  | EGLNativeWindowType window = NULL; //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_1_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_1(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(); | 
|  | } | 
|  |  | 
|  | // Dimension class to hwc_rect conversion | 
|  | HwcTestDim::operator hwc_rect() const | 
|  | { | 
|  | hwc_rect rect; | 
|  |  | 
|  | rect.left = rect.top = 0; | 
|  |  | 
|  | rect.right = this->_w; | 
|  | rect.bottom = this->_h; | 
|  |  | 
|  | return rect; | 
|  | } | 
|  |  | 
|  | // 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; | 
|  | } | 
|  |  | 
|  | // Look up and return pointer to structure with the characteristics | 
|  | // of the graphic format specified by the id parameter.  Search failure | 
|  | // indicated by the return of NULL. | 
|  | const struct hwcTestGraphicFormat *hwcTestGraphicFormatLookup(uint32_t id) | 
|  | { | 
|  | for (unsigned int n1 = 0; n1 < NUMA(hwcTestGraphicFormat); n1++) { | 
|  | if (id == hwcTestGraphicFormat[n1].format) { | 
|  | 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_display_contents_1_t *hwcTestCreateLayerList(size_t numLayers) | 
|  | { | 
|  | hwc_display_contents_1_t *list; | 
|  |  | 
|  | size_t size = sizeof(hwc_display_contents_1_t) + numLayers * sizeof(hwc_layer_1_t); | 
|  | if ((list = (hwc_display_contents_1_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_display_contents_1_t *list) | 
|  | { | 
|  | free(list); | 
|  | } | 
|  |  | 
|  | // Display the settings of the layer list pointed to by list | 
|  | void hwcTestDisplayList(hwc_display_contents_1_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].sourceCrop.right | 
|  | - list->hwLayers[layer].sourceCrop.left) | 
|  | / (float) (list->hwLayers[layer].displayFrame.right | 
|  | - list->hwLayers[layer].displayFrame.left), | 
|  | (float) (list->hwLayers[layer].sourceCrop.bottom | 
|  | - list->hwLayers[layer].sourceCrop.top) | 
|  | / (float) (list->hwLayers[layer].displayFrame.bottom | 
|  | - list->hwLayers[layer].displayFrame.top)); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Display List Prepare Modifiable | 
|  | * | 
|  | * Displays the portions of a list that are meant to be modified by | 
|  | * a prepare call. | 
|  | */ | 
|  | void hwcTestDisplayListPrepareModifiable(hwc_display_contents_1_t *list) | 
|  | { | 
|  | uint32_t numOverlays = 0; | 
|  | for (unsigned int layer = 0; layer < list->numHwLayers; layer++) { | 
|  | if (list->hwLayers[layer].compositionType == HWC_OVERLAY) { | 
|  | numOverlays++; | 
|  | } | 
|  | 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" : ""); | 
|  | } | 
|  | testPrintI("    numOverlays: %u", numOverlays); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Display List Handles | 
|  | * | 
|  | * Displays the handles of all the graphic buffers in the list. | 
|  | */ | 
|  | void hwcTestDisplayListHandles(hwc_display_contents_1_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_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}, | 
|  | }; | 
|  |  | 
|  | 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++) { | 
|  | 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_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 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(""); | 
|  | } |