replicant-frameworks_native/opengl/tests/hwc/hwcRects.cpp
Andy McFadden 6ef57d7b36 Restore old OpenGL tests
These tests call android_createDisplaySurface() to get a
FramebufferNativeWindow that is passed to EGL.  This relies on the
existence of the framebuffer HAL, which is not supported on many
recent devices.

This change adds a new "window surface" object that the tests
can use to get a window from SurfaceFlinger instead.  All tests
except for the HWC tests now appear to do things.

The HWC tests don't do anything useful, but they no longer depend
on the android_createDisplaySurface() function.

Bug 13323813

Change-Id: I2cbfbacb3452fb658c29e945b0c7ae7c94c1a4ba
2014-03-06 16:46:59 -08:00

578 lines
19 KiB
C++

/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Hardware Composer Rectangles
*
* Synopsis
* hwcRects [options] (graphicFormat displayFrame [attributes],)...
* options:
* -D #.## - End of test delay
* -v - Verbose
*
* graphic formats:
* RGBA8888 (reference frame default)
* RGBX8888
* RGB888
* RGB565
* BGRA8888
* RGBA5551
* RGBA4444
* YV12
*
* displayFrame
* [left, top, right, bottom]
*
* attributes:
* transform: none | fliph | flipv | rot90 | rot180 | rot270
* blend: none | premult | coverage
* color: [0.##, 0.##, 0.##]
* alpha: 0.##
* sourceDim: [width, height]
* sourceCrop: [left, top, right, bottom]
*
* Example:
* # White YV12 rectangle, with overlapping turquoise
* # RGBA8888 rectangle at 30%% (alpha: 0.7) transparency
* hwcRects -v -D 30.0 \
* YV12 [50, 80, 200, 300] transform: none \
* color: [1.0, 0.5, 0.5], \
* RGBA8888 [100, 150, 300, 400] blend: coverage \
* color: [0.251, 0.878, 0.816] alpha: 0.7 \
* sourceDim: [50, 60] sourceCrop: [5, 8, 12, 15]
*
* Description
* Constructs a Hardware Composer (HWC) list of frames from
* command-line specified parameters. Then sends it to the HWC
* be rendered. The intended purpose of this tool is as a means to
* reproduce and succinctly specify an observed HWC operation, with
* no need to modify/compile a program.
*
* The command-line syntax consists of a few standard command-line
* options and then a description of one or more frames. The frame
* descriptions are separated from one another via a comma. The
* beginning of a frame description requires the specification
* of the graphic format and then the display frame rectangle where
* the frame will be displayed. The display frame rectangle is
* specified as follows, with the right and bottom coordinates being
* exclusive values:
*
* [left, top, right, bottom]
*
* After these two required parameters each frame description can
* specify 1 or more optional attributes. The name of each optional
* attribute is preceded by a colon. The current implementation
* then requires white space after the colon and then the value of
* the attribute is specified. See the synopsis section above for
* a list of attributes and the format of their expected value.
*/
#include <algorithm>
#include <assert.h>
#include <cerrno>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <istream>
#include <libgen.h>
#include <list>
#include <sched.h>
#include <sstream>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <ui/GraphicBuffer.h>
#define LOG_TAG "hwcRectsTest"
#include <utils/Log.h>
#include <testUtil.h>
#include <hardware/hwcomposer.h>
#include <glTestLib.h>
#include "hwcTestLib.h"
using namespace std;
using namespace android;
// Defaults
const bool defaultVerbose = false;
const float defaultEndDelay = 2.0; // Default delay after rendering graphics
const uint32_t defaultFormat = HAL_PIXEL_FORMAT_RGBA_8888;
const int32_t defaultTransform = 0;
const uint32_t defaultBlend = HWC_BLENDING_NONE;
const ColorFract defaultColor(0.5, 0.5, 0.5);
const float defaultAlpha = 1.0; // Opaque
const HwcTestDim defaultSourceDim(1, 1);
const struct hwc_rect defaultSourceCrop = {0, 0, 1, 1};
const struct hwc_rect defaultDisplayFrame = {0, 0, 100, 100};
// Defines
#define MAXCMD 200
#define CMD_STOP_FRAMEWORK "stop 2>&1"
#define CMD_START_FRAMEWORK "start 2>&1"
// Macros
#define NUMA(a) (sizeof(a) / sizeof(a [0])) // Num elements in an array
// Local types
class Rectangle {
public:
Rectangle() : format(defaultFormat), transform(defaultTransform),
blend(defaultBlend), color(defaultColor),
alpha(defaultAlpha), sourceDim(defaultSourceDim),
sourceCrop(defaultSourceCrop),
displayFrame(defaultDisplayFrame) {};
uint32_t format;
uint32_t transform;
int32_t blend;
ColorFract color;
float alpha;
HwcTestDim sourceDim;
struct hwc_rect sourceCrop;
struct hwc_rect displayFrame;
sp<GraphicBuffer> texture;
};
// Globals
list<Rectangle> rectangle;
static const int texUsage = GraphicBuffer::USAGE_HW_TEXTURE |
GraphicBuffer::USAGE_SW_WRITE_RARELY;
static hwc_composer_device_1_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];
testSetLogCatTag(LOG_TAG);
// 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_display_contents_1_t *list;
list = hwcTestCreateLayerList(rectangle.size());
if (list == NULL) {
testPrintE("hwcTestCreateLayerList failed");
exit(5);
}
hwc_layer_1_t *layer = &list->hwLayers[0];
for (std::list<Rectangle>::iterator it = rectangle.begin();
it != rectangle.end(); ++it, ++layer) {
layer->handle = it->texture->handle;
layer->blending = it->blend;
layer->transform = it->transform;
layer->sourceCrop = it->sourceCrop;
layer->displayFrame = it->displayFrame;
layer->visibleRegionScreen.numRects = 1;
layer->visibleRegionScreen.rects = &layer->displayFrame;
}
// Perform prepare operation
if (verbose) { testPrintI("Prepare:"); hwcTestDisplayList(list); }
hwcDevice->prepare(hwcDevice, 1, &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); }
list->dpy = dpy;
list->sur = surface;
hwcDevice->set(hwcDevice, 1, &list);
testDelay(endDelay);
// Start framework
rv = snprintf(cmd, sizeof(cmd), "%s", CMD_START_FRAMEWORK);
if (rv >= (signed) sizeof(cmd) - 1) {
testPrintE("Command too long for: %s", CMD_START_FRAMEWORK);
exit(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]");
}