Brian Swetland | 2c7b08a | 2013-03-06 17:16:31 -0800 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2013 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | #include <stdlib.h> |
| 18 | #include <stdio.h> |
| 19 | #include <stdarg.h> |
| 20 | |
| 21 | #include <EGL/egl.h> |
| 22 | #include <GLES2/gl2.h> |
| 23 | |
| 24 | #include <system/graphics.h> |
| 25 | |
| 26 | #include "util.h" |
| 27 | |
| 28 | void matrix_init_ortho(GLfloat *m, float w, float h) { |
| 29 | m[0] = 2.0 / w; |
| 30 | m[1] = 0.0; |
| 31 | m[2] = 0.0; |
| 32 | m[3] = -1.0; |
| 33 | m[4] = 0.0; |
| 34 | m[5] = 2.0 / h; |
| 35 | m[6] = 0.0; |
| 36 | m[7] = -1.0; |
| 37 | m[8] = 0.0; |
| 38 | m[9] = 0.0; |
Chih-Hung Hsieh | 4224d9e | 2017-12-01 11:28:37 -0800 | [diff] [blame] | 39 | m[10] = -1.0; |
Brian Swetland | 2c7b08a | 2013-03-06 17:16:31 -0800 | [diff] [blame] | 40 | m[11] = 0.0; |
| 41 | m[12] = 0.0; |
| 42 | m[13] = 0.0; |
| 43 | m[14] = 0.0; |
| 44 | m[15] = 1.0; |
| 45 | } |
| 46 | |
| 47 | static GLuint load_shader(GLenum shaderType, const char *src) { |
| 48 | GLint status = 0, len = 0; |
| 49 | GLuint shader; |
| 50 | |
| 51 | if (!(shader = glCreateShader(shaderType))) |
| 52 | return 0; |
| 53 | |
| 54 | glShaderSource(shader, 1, &src, NULL); |
| 55 | glCompileShader(shader); |
| 56 | glGetShaderiv(shader, GL_COMPILE_STATUS, &status); |
| 57 | |
| 58 | if (status) |
| 59 | return shader; |
| 60 | |
| 61 | glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &len); |
| 62 | if (len) { |
| 63 | char *msg = malloc(len); |
| 64 | if (msg) { |
| 65 | glGetShaderInfoLog(shader, len, NULL, msg); |
| 66 | msg[len-1] = 0; |
| 67 | fprintf(stderr, "error compiling shader:\n%s\n", msg); |
| 68 | free(msg); |
| 69 | } |
| 70 | } |
| 71 | glDeleteShader(shader); |
| 72 | return 0; |
| 73 | } |
| 74 | |
| 75 | GLuint load_program(const char *vert_src, const char *frag_src) { |
| 76 | GLuint vert, frag, prog; |
| 77 | GLint status = 0, len = 0; |
| 78 | |
| 79 | if (!(vert = load_shader(GL_VERTEX_SHADER, vert_src))) |
| 80 | return 0; |
| 81 | if (!(frag = load_shader(GL_FRAGMENT_SHADER, frag_src))) |
| 82 | goto fail_frag; |
| 83 | if (!(prog = glCreateProgram())) |
| 84 | goto fail_prog; |
| 85 | |
| 86 | glAttachShader(prog, vert); |
| 87 | glAttachShader(prog, frag); |
| 88 | glLinkProgram(prog); |
| 89 | |
| 90 | glGetProgramiv(prog, GL_LINK_STATUS, &status); |
| 91 | if (status) |
| 92 | return prog; |
| 93 | |
| 94 | glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &len); |
| 95 | if (len) { |
| 96 | char *buf = (char*) malloc(len); |
| 97 | if (buf) { |
| 98 | glGetProgramInfoLog(prog, len, NULL, buf); |
| 99 | buf[len-1] = 0; |
| 100 | fprintf(stderr, "error linking program:\n%s\n", buf); |
| 101 | free(buf); |
| 102 | } |
| 103 | } |
| 104 | glDeleteProgram(prog); |
| 105 | fail_prog: |
| 106 | glDeleteShader(frag); |
| 107 | fail_frag: |
| 108 | glDeleteShader(vert); |
| 109 | return 0; |
| 110 | } |
| 111 | |
| 112 | int select_config_for_window(EGLDisplay dpy, EGLint *attr, |
| 113 | unsigned format, EGLConfig *config) { |
Chih-Hung Hsieh | 4224d9e | 2017-12-01 11:28:37 -0800 | [diff] [blame] | 114 | EGLint R,G,B,A; |
Brian Swetland | 2c7b08a | 2013-03-06 17:16:31 -0800 | [diff] [blame] | 115 | EGLint i, n, max; |
| 116 | EGLConfig *cfg; |
| 117 | |
| 118 | switch (format) { |
| 119 | case HAL_PIXEL_FORMAT_RGBA_8888: |
| 120 | case HAL_PIXEL_FORMAT_BGRA_8888: |
| 121 | R = G = B = A = 8; |
| 122 | break; |
| 123 | case HAL_PIXEL_FORMAT_RGB_565: |
| 124 | R = 5; G = 6; B = 5; A = 0; |
| 125 | break; |
| 126 | default: |
| 127 | fprintf(stderr, "unknown fb pixel format %d\n", format); |
| 128 | return -1; |
| 129 | } |
| 130 | |
| 131 | if (eglGetConfigs(dpy, NULL, 0, &max) == EGL_FALSE) { |
| 132 | fprintf(stderr, "no EGL configurations available?!\n"); |
| 133 | return -1; |
| 134 | } |
| 135 | |
| 136 | cfg = (EGLConfig*) malloc(sizeof(EGLConfig) * max); |
| 137 | if (!cfg) |
| 138 | return -1; |
| 139 | |
| 140 | if (eglChooseConfig(dpy, attr, cfg, max, &n) == EGL_FALSE) { |
| 141 | fprintf(stderr, "eglChooseConfig failed\n"); |
| 142 | return -1; |
| 143 | } |
| 144 | |
| 145 | for (i = 0; i < n; i++) { |
| 146 | EGLint r,g,b,a; |
| 147 | eglGetConfigAttrib(dpy, cfg[i], EGL_RED_SIZE, &r); |
| 148 | eglGetConfigAttrib(dpy, cfg[i], EGL_GREEN_SIZE, &g); |
| 149 | eglGetConfigAttrib(dpy, cfg[i], EGL_BLUE_SIZE, &b); |
| 150 | eglGetConfigAttrib(dpy, cfg[i], EGL_ALPHA_SIZE, &a); |
| 151 | if (r == R && g == G && b == B && a == A) { |
| 152 | *config = cfg[i]; |
| 153 | free(cfg); |
| 154 | return 0; |
| 155 | } |
| 156 | } |
| 157 | |
| 158 | fprintf(stderr, "cannot find matching config\n"); |
| 159 | free(cfg); |
| 160 | return -1; |
| 161 | } |
| 162 | |
| 163 | static struct CNativeWindow *_cnw = 0; |
| 164 | |
| 165 | int egl_create(EGLDisplay *_display, EGLSurface *_surface, int *_w, int *_h) { |
| 166 | EGLBoolean res; |
| 167 | EGLConfig config = { 0 }; |
| 168 | EGLint context_attrs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; |
| 169 | EGLint config_attrs[] = { |
| 170 | EGL_SURFACE_TYPE, EGL_WINDOW_BIT, |
| 171 | EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, |
| 172 | EGL_NONE }; |
| 173 | EGLint major, minor; |
| 174 | EGLContext context; |
| 175 | EGLSurface surface; |
| 176 | EGLint w, h; |
| 177 | EGLDisplay display; |
| 178 | EGLNativeWindowType window; |
| 179 | unsigned width, height, format; |
| 180 | struct CNativeWindow *cnw; |
| 181 | |
| 182 | display = eglGetDisplay(EGL_DEFAULT_DISPLAY); |
| 183 | if (display == EGL_NO_DISPLAY) |
| 184 | return -1; |
| 185 | |
| 186 | if (!(res = eglInitialize(display, &major, &minor))) |
| 187 | return -1; |
| 188 | |
| 189 | fprintf(stderr, "egl version: %d.%d\n", major, minor); |
| 190 | |
| 191 | if ((cnw = cnw_create()) == 0) |
| 192 | return -1; |
| 193 | |
| 194 | cnw_info(cnw, &width, &height, &format); |
| 195 | window = (EGLNativeWindowType) cnw; |
| 196 | |
| 197 | if ((res = select_config_for_window(display, config_attrs, format, &config))) |
| 198 | goto fail; |
| 199 | |
| 200 | surface = eglCreateWindowSurface(display, config, window, NULL); |
| 201 | if (surface == EGL_NO_SURFACE) |
| 202 | goto fail; |
| 203 | |
| 204 | context = eglCreateContext(display, config, EGL_NO_CONTEXT, context_attrs); |
| 205 | if (context == EGL_NO_CONTEXT) |
| 206 | goto fail; |
| 207 | |
| 208 | if (!(res = eglMakeCurrent(display, surface, surface, context))) |
| 209 | goto fail; |
| 210 | |
| 211 | eglQuerySurface(display, surface, EGL_WIDTH, &w); |
| 212 | eglQuerySurface(display, surface, EGL_HEIGHT, &h); |
| 213 | |
| 214 | fprintf(stderr, "window: %d x %d\n", w, h); |
| 215 | |
| 216 | *_display = display; |
| 217 | *_surface = surface; |
| 218 | *_w = w; |
| 219 | *_h = h; |
| 220 | |
| 221 | _cnw = cnw; |
| 222 | return 0; |
| 223 | |
| 224 | fail: |
| 225 | cnw_destroy(cnw); |
| 226 | return -1; |
| 227 | } |
| 228 | |
| 229 | void egl_destroy(EGLDisplay display, EGLSurface surface) { |
| 230 | if (_cnw) { |
| 231 | eglDestroySurface(display, surface); |
| 232 | eglTerminate(display); |
| 233 | cnw_destroy(_cnw); |
| 234 | _cnw = 0; |
| 235 | } |
| 236 | } |