/* * 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; } }