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
28void 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;
39	m[10] -1.0;
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
47static 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
75GLuint 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);
105fail_prog:
106	glDeleteShader(frag);
107fail_frag:
108	glDeleteShader(vert);
109	return 0;
110}
111
112int select_config_for_window(EGLDisplay dpy, EGLint *attr,
113	unsigned format, EGLConfig *config) {
114	EGLint R,G,B,A,r,g,b,a;
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
163static struct CNativeWindow *_cnw = 0;
164
165int 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
224fail:
225	cnw_destroy(cnw);
226	return -1;
227}
228
229void 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}
237