hwcomposer commandline test(s)

Add cnativewindow which provides a minimal bridge between EGL and hwcomposer or fbhal.
Add test-arrows, a trivial GLES2 test program to exercise this.

Change-Id: I60ece4378def6b6eda55437c215fc46a180ad7a3
diff --git a/tests/hwc/util.c b/tests/hwc/util.c
new file mode 100644
index 0000000..8931305
--- /dev/null
+++ b/tests/hwc/util.c
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+#include <EGL/egl.h>
+#include <GLES2/gl2.h>
+
+#include <system/graphics.h>
+
+#include "util.h"
+
+void matrix_init_ortho(GLfloat *m, float w, float h) {
+	m[0] = 2.0 / w;
+	m[1] = 0.0;
+	m[2] = 0.0;
+	m[3] = -1.0;
+	m[4] = 0.0;
+	m[5] = 2.0 / h;
+	m[6] = 0.0;
+	m[7] = -1.0;
+	m[8] = 0.0;
+	m[9] = 0.0;
+	m[10] -1.0;
+	m[11] = 0.0;
+	m[12] = 0.0;
+	m[13] = 0.0;
+	m[14] = 0.0;
+	m[15] = 1.0;
+}
+
+static GLuint load_shader(GLenum shaderType, const char *src) {
+	GLint status = 0, len = 0;
+	GLuint shader;
+
+	if (!(shader = glCreateShader(shaderType)))
+		return 0;
+
+	glShaderSource(shader, 1, &src, NULL);
+	glCompileShader(shader);
+	glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
+
+	if (status)
+		return shader;
+
+	glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &len);
+	if (len) {
+		char *msg = malloc(len);
+		if (msg) {
+			glGetShaderInfoLog(shader, len, NULL, msg);
+			msg[len-1] = 0;
+			fprintf(stderr, "error compiling shader:\n%s\n", msg);
+			free(msg);
+		}
+	}
+	glDeleteShader(shader);
+	return 0;
+}
+
+GLuint load_program(const char *vert_src, const char *frag_src) {
+	GLuint vert, frag, prog;
+	GLint status = 0, len = 0;
+
+	if (!(vert = load_shader(GL_VERTEX_SHADER, vert_src)))
+		return 0;
+	if (!(frag = load_shader(GL_FRAGMENT_SHADER, frag_src)))
+		goto fail_frag;
+	if (!(prog = glCreateProgram()))
+		goto fail_prog;
+
+	glAttachShader(prog, vert);
+	glAttachShader(prog, frag);
+	glLinkProgram(prog);
+
+	glGetProgramiv(prog, GL_LINK_STATUS, &status);
+	if (status)
+		return prog;
+
+	glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &len);
+	if (len) {
+		char *buf = (char*) malloc(len);
+		if (buf) {
+			glGetProgramInfoLog(prog, len, NULL, buf);
+			buf[len-1] = 0;
+			fprintf(stderr, "error linking program:\n%s\n", buf);
+			free(buf);
+		}
+	}
+	glDeleteProgram(prog);
+fail_prog:
+	glDeleteShader(frag);
+fail_frag:
+	glDeleteShader(vert);
+	return 0;
+}
+
+int select_config_for_window(EGLDisplay dpy, EGLint *attr,
+	unsigned format, EGLConfig *config) {
+	EGLint R,G,B,A,r,g,b,a;
+	EGLint i, n, max;
+	EGLConfig *cfg;
+
+	switch (format) {
+	case HAL_PIXEL_FORMAT_RGBA_8888:
+	case HAL_PIXEL_FORMAT_BGRA_8888:
+		R = G = B = A = 8;
+		break;
+	case HAL_PIXEL_FORMAT_RGB_565:
+		R = 5; G = 6; B = 5; A = 0;
+		break;
+	default:
+		fprintf(stderr, "unknown fb pixel format %d\n", format);
+		return -1;
+	}
+
+	if (eglGetConfigs(dpy, NULL, 0, &max) == EGL_FALSE) {
+		fprintf(stderr, "no EGL configurations available?!\n");
+		return -1;
+	}
+
+	cfg = (EGLConfig*) malloc(sizeof(EGLConfig) * max);
+	if (!cfg)
+		return -1;
+
+	if (eglChooseConfig(dpy, attr, cfg, max, &n) == EGL_FALSE) {
+		fprintf(stderr, "eglChooseConfig failed\n");
+		return -1;
+	}
+
+	for (i = 0; i < n; i++) {
+		EGLint r,g,b,a;
+		eglGetConfigAttrib(dpy, cfg[i], EGL_RED_SIZE,   &r);
+		eglGetConfigAttrib(dpy, cfg[i], EGL_GREEN_SIZE, &g);
+		eglGetConfigAttrib(dpy, cfg[i], EGL_BLUE_SIZE,  &b);
+		eglGetConfigAttrib(dpy, cfg[i], EGL_ALPHA_SIZE, &a);
+		if (r == R && g == G && b == B && a == A) {
+			*config = cfg[i];
+			free(cfg);
+			return 0;
+		}
+	}
+
+	fprintf(stderr, "cannot find matching config\n");
+	free(cfg);
+	return -1;
+}
+
+static struct CNativeWindow *_cnw = 0;
+
+int egl_create(EGLDisplay *_display, EGLSurface *_surface, int *_w, int *_h) {
+	EGLBoolean res;
+	EGLConfig config = { 0 };
+	EGLint context_attrs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
+	EGLint config_attrs[] = {
+		EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+		EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+		EGL_NONE };
+	EGLint major, minor;
+	EGLContext context;
+	EGLSurface surface;
+	EGLint w, h;
+	EGLDisplay display;
+	EGLNativeWindowType window;
+	unsigned width, height, format;
+	struct CNativeWindow *cnw;
+
+	display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+	if (display == EGL_NO_DISPLAY)
+		return -1;
+
+	if (!(res = eglInitialize(display, &major, &minor)))
+		return -1;
+
+	fprintf(stderr, "egl version: %d.%d\n", major, minor);
+
+	if ((cnw = cnw_create()) == 0)
+		return -1;
+
+	cnw_info(cnw, &width, &height, &format);
+	window = (EGLNativeWindowType) cnw;
+
+	if ((res = select_config_for_window(display, config_attrs, format, &config)))
+		goto fail;
+
+	surface = eglCreateWindowSurface(display, config, window, NULL);
+	if (surface == EGL_NO_SURFACE)
+		goto fail;
+
+	context = eglCreateContext(display, config, EGL_NO_CONTEXT, context_attrs);
+	if (context == EGL_NO_CONTEXT)
+		goto fail;
+
+	if (!(res = eglMakeCurrent(display, surface, surface, context)))
+		goto fail;
+
+	eglQuerySurface(display, surface, EGL_WIDTH, &w);
+	eglQuerySurface(display, surface, EGL_HEIGHT, &h);
+
+	fprintf(stderr, "window: %d x %d\n", w, h);
+
+	*_display = display;
+	*_surface = surface;
+	*_w = w;
+	*_h = h;
+
+	_cnw = cnw;
+	return 0;
+
+fail:
+	cnw_destroy(cnw);
+	return -1;
+}
+
+void egl_destroy(EGLDisplay display, EGLSurface surface) {
+	if (_cnw) {
+		eglDestroySurface(display, surface);
+		eglTerminate(display);
+		cnw_destroy(_cnw);
+		_cnw = 0;
+	}
+}