3b201dbc5820d0eb2c3272d2f76b2142157fc962
[libpicofe.git] / gl.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <assert.h>
5
6 #include <EGL/egl.h>
7 #include <GLES/gl.h>
8 #include "gl_loader.h"
9 #include "gl_platform.h"
10 #include "gl.h"
11
12 static EGLDisplay edpy = EGL_NO_DISPLAY;
13 static EGLSurface esfc = EGL_NO_SURFACE;
14 static EGLContext ectxt = EGL_NO_CONTEXT;
15
16 static GLuint texture_name;
17
18 /* for external flips */
19 void *gl_es_display;
20 void *gl_es_surface;
21
22 static int tex_w, tex_h;
23 static void *tex_mem;
24 static int flip_old_w, flip_old_h;
25
26 static int gl_have_error(const char *name)
27 {
28         GLenum e = glGetError();
29         if (e != GL_NO_ERROR) {
30                 fprintf(stderr, "GL error: %s %x\n", name, e);
31                 return 1;
32         }
33         return 0;
34 }
35
36 static int gles_have_error(const char *name)
37 {
38         EGLint e = eglGetError();
39         if (e != EGL_SUCCESS) {
40                 fprintf(stderr, "%s %x\n", name, e);
41                 return 1;
42         }
43         return 0;
44 }
45
46 int gl_init(void *display, int *quirks)
47 {
48         int retval = -1;
49         int ret;
50
51         ret = gl_platform_init(&display, quirks);
52         if (ret != 0) {
53                 fprintf(stderr, "gl_platform_init failed with %d\n", ret);
54                 return retval;
55         }
56
57         edpy = eglGetDisplay((EGLNativeDisplayType)display);
58         if (edpy == EGL_NO_DISPLAY) {
59                 fprintf(stderr, "Failed to get EGL display\n");
60                 goto out;
61         }
62
63         if (!eglInitialize(edpy, NULL, NULL)) {
64                 fprintf(stderr, "Failed to initialize EGL\n");
65                 goto out;
66         }
67         retval = 0;
68
69 out:
70         if (retval && edpy != EGL_NO_DISPLAY)
71                 gl_shutdown();
72         return retval;
73 }
74
75 int gl_create(void *window, int *quirks, int w, int h)
76 {
77         EGLConfig ecfg = NULL;
78         EGLint num_config;
79         int retval = -1;
80         int ret;
81         EGLint config_attr[] =
82         {
83                 EGL_NONE
84         };
85
86         ret = gl_platform_create(&window, quirks);
87         if (ret != 0) {
88                 fprintf(stderr, "gl_platform_init failed with %d\n", ret);
89                 return retval;
90         }
91
92         flip_old_w = flip_old_h = 0;
93         for (tex_w = 1; tex_w < w; tex_w *= 2)
94                 ;
95         for (tex_h = 1; tex_h < h; tex_h *= 2)
96                 ;
97         tex_mem = realloc(tex_mem, tex_w * tex_h * 2);
98         if (tex_mem == NULL) {
99                 fprintf(stderr, "OOM\n");
100                 goto out;
101         }
102         memset(tex_mem, 0, tex_w * tex_h * 2);
103
104         if (!eglChooseConfig(edpy, config_attr, &ecfg, 1, &num_config)) {
105                 fprintf(stderr, "Failed to choose config (%x)\n", eglGetError());
106                 goto out;
107         }
108
109         if (ecfg == NULL || num_config == 0) {
110                 fprintf(stderr, "No EGL configs available\n");
111                 goto out;
112         }
113
114         esfc = eglCreateWindowSurface(edpy, ecfg,
115                 (EGLNativeWindowType)window, NULL);
116         if (esfc == EGL_NO_SURFACE) {
117                 fprintf(stderr, "Unable to create EGL surface (%x)\n",
118                         eglGetError());
119                 goto out;
120         }
121
122         ectxt = eglCreateContext(edpy, ecfg, EGL_NO_CONTEXT, NULL);
123         if (ectxt == EGL_NO_CONTEXT) {
124                 fprintf(stderr, "Unable to create EGL context (%x)\n",
125                         eglGetError());
126                 // on mesa, some distros disable ES1.x but compat GL still works
127                 ret = eglBindAPI(EGL_OPENGL_API);
128                 if (!ret) {
129                         fprintf(stderr, "eglBindAPI: %x\n", eglGetError());
130                         goto out;
131                 }
132                 ectxt = eglCreateContext(edpy, ecfg, EGL_NO_CONTEXT, NULL);
133                 if (ectxt == EGL_NO_CONTEXT) {
134                         fprintf(stderr, "giving up on EGL context (%x)\n",
135                                 eglGetError());
136                         goto out;
137                 }
138         }
139
140         ret = eglMakeCurrent(edpy, esfc, esfc, ectxt);
141         if (!ret) {
142                 fprintf(stderr, "eglMakeCurrent: %x\n", eglGetError());
143                 goto out;
144         }
145         
146         ret = *quirks & GL_QUIRK_VSYNC_ON ? 1 : 0;
147         eglSwapInterval(edpy, ret);
148
149         // 1.x (fixed-function) only
150         glEnable(GL_TEXTURE_2D);
151         glGetError();
152
153         assert(!texture_name);
154
155         glGenTextures(1, &texture_name);
156         if (gl_have_error("glGenTextures"))
157                 goto out;
158
159         glBindTexture(GL_TEXTURE_2D, texture_name);
160         if (gl_have_error("glBindTexture"))
161                 goto out;
162
163         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tex_w, tex_h, 0, GL_RGB,
164                 GL_UNSIGNED_SHORT_5_6_5, tex_mem);
165         if (gl_have_error("glTexImage2D"))
166                 goto out;
167
168         // no mipmaps
169         ret = *quirks & GL_QUIRK_SCALING_NEAREST ? GL_NEAREST : GL_LINEAR;
170         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, ret);
171         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, ret);
172
173         //glViewport(0, 0, 512, 512);
174         glLoadIdentity();
175         glFrontFace(GL_CW);
176         glEnable(GL_CULL_FACE);
177
178         glEnableClientState(GL_TEXTURE_COORD_ARRAY);
179         glEnableClientState(GL_VERTEX_ARRAY);
180
181         if (gl_have_error("init"))
182                 goto out;
183
184         gl_es_display = (void *)edpy;
185         gl_es_surface = (void *)esfc;
186         retval = 0;
187 out:
188         if (retval && edpy != EGL_NO_DISPLAY)
189                 gl_destroy();
190         return retval;
191 }
192
193 void gl_announce(void)
194 {
195         printf("GL_RENDERER: %s\n", (char *)glGetString(GL_RENDERER));
196         printf("GL_VERSION: %s\n", (char *)glGetString(GL_VERSION));
197 }
198
199 static const float default_vertices[] = {
200         -1.0f,  1.0f,  0.0f, // 0    0  1
201          1.0f,  1.0f,  0.0f, // 1  ^
202         -1.0f, -1.0f,  0.0f, // 2  | 2  3
203          1.0f, -1.0f,  0.0f, // 3  +-->
204 };
205
206 static float texture[] = {
207         0.0f, 0.0f, // we flip this:
208         1.0f, 0.0f, // v^
209         0.0f, 1.0f, //  |  u
210         1.0f, 1.0f, //  +-->
211 };
212
213 int gl_flip_v(const void *fb, int w, int h, const float *vertices)
214 {
215         gl_have_error("pre-flip unknown");
216
217         glBindTexture(GL_TEXTURE_2D, texture_name);
218         if (gl_have_error("glBindTexture"))
219                 return -1;
220
221         if (fb != NULL) {
222                 if (w != flip_old_w || h != flip_old_h) {
223                         float f_w = (float)w / tex_w;
224                         float f_h = (float)h / tex_h;
225                         texture[1*2 + 0] = f_w;
226                         texture[2*2 + 1] = f_h;
227                         texture[3*2 + 0] = f_w;
228                         texture[3*2 + 1] = f_h;
229                         flip_old_w = w;
230                         flip_old_h = h;
231                 }
232
233                 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h,
234                         GL_RGB, GL_UNSIGNED_SHORT_5_6_5, fb);
235                 if (gl_have_error("glTexSubImage2D")) {
236                         fprintf(stderr, "  %dx%d t: %dx%d %p\n", w, h, tex_w, tex_h, fb);
237                         return -1;
238                 }
239         }
240
241         glVertexPointer(3, GL_FLOAT, 0, vertices ? vertices : default_vertices);
242         glTexCoordPointer(2, GL_FLOAT, 0, texture);
243         glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
244         if (gl_have_error("glDrawArrays"))
245                 return -1;
246
247         eglSwapBuffers(edpy, esfc);
248         if (gles_have_error("eglSwapBuffers"))
249                 return -1;
250
251         return 0;
252 }
253
254 int gl_flip(const void *fb, int w, int h)
255 {
256         return gl_flip_v(fb, w, h, NULL);
257 }
258
259 // to be used once after exiting menu, etc
260 void gl_clear(void)
261 {
262         glClearColor(0, 0, 0, 0);
263         glClear(GL_COLOR_BUFFER_BIT);
264         eglSwapBuffers(edpy, esfc);
265         glClear(GL_COLOR_BUFFER_BIT);
266         eglSwapBuffers(edpy, esfc);
267         glClear(GL_COLOR_BUFFER_BIT);
268         gl_have_error("glClear");
269 }
270
271 void gl_destroy(void)
272 {
273         if (edpy == EGL_NO_DISPLAY)
274                 return; // nothing to do
275
276         // sometimes there is an error... from somewhere?
277         //gl_have_error("finish");
278         glGetError();
279
280         if (texture_name)
281         {
282                 glDeleteTextures(1, &texture_name);
283                 gl_have_error("glDeleteTextures");
284                 texture_name = 0;
285         }
286
287         eglMakeCurrent(edpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
288         if (ectxt != EGL_NO_CONTEXT) {
289                 eglDestroyContext(edpy, ectxt);
290                 ectxt = EGL_NO_CONTEXT;
291         }
292         if (esfc != EGL_NO_SURFACE) {
293                 eglDestroySurface(edpy, esfc);
294                 esfc = EGL_NO_SURFACE;
295         }
296
297         gl_es_surface = (void *)esfc;
298
299         if (tex_mem) free(tex_mem);
300         tex_mem = NULL;
301
302         gl_platform_destroy();
303 }
304
305 void gl_shutdown(void)
306 {
307         if (edpy != EGL_NO_DISPLAY) {
308                 eglTerminate(edpy);
309                 edpy = EGL_NO_DISPLAY;
310         }
311
312         gl_es_display = (void *)edpy;
313
314         gl_platform_shutdown();
315 }