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;
+ }
+}