make gl layer reinitializable
[libpicofe.git] / gl.c
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 #include <EGL/egl.h>
5 #include <GLES/gl.h>
6 #include "gl_platform.h"
7 #include "gl.h"
8
9 static EGLDisplay edpy;
10 static EGLSurface esfc;
11 static EGLContext ectxt;
12
13 static GLuint texture_name;
14
15 /* for external flips */
16 void *gl_es_display;
17 void *gl_es_surface;
18
19 static int tex_w, tex_h;
20 static void *tex_mem;
21
22 static int gl_have_error(const char *name)
23 {
24         GLenum e = glGetError();
25         if (e != GL_NO_ERROR) {
26                 fprintf(stderr, "GL error: %s %x\n", name, e);
27                 return 1;
28         }
29         return 0;
30 }
31
32 static int gles_have_error(const char *name)
33 {
34         EGLint e = eglGetError();
35         if (e != EGL_SUCCESS) {
36                 fprintf(stderr, "%s %x\n", name, e);
37                 return 1;
38         }
39         return 0;
40 }
41
42 int gl_init(void *display, void *window, int *quirks, int w, int h)
43 {
44         EGLConfig ecfg = NULL;
45         EGLint num_config;
46         int retval = -1;
47         int ret;
48         EGLint attr[] =
49         {
50                 EGL_NONE
51         };
52
53         ret = gl_platform_init(&display, &window, quirks);
54         if (ret != 0) {
55                 fprintf(stderr, "gl_platform_init failed with %d\n", ret);
56                 goto out;
57         }
58
59         for (tex_w = 1; tex_w < w; tex_w *= 2);
60         for (tex_h = 1; tex_h < h; tex_h *= 2);
61         tex_mem = realloc(tex_mem, tex_w * tex_h * 2);
62         if (tex_mem == NULL) {
63                 fprintf(stderr, "OOM\n");
64                 goto out;
65         }
66
67         edpy = eglGetDisplay((EGLNativeDisplayType)display);
68         if (edpy == EGL_NO_DISPLAY) {
69                 fprintf(stderr, "Failed to get EGL display\n");
70                 goto out;
71         }
72
73         if (!eglInitialize(edpy, NULL, NULL)) {
74                 fprintf(stderr, "Failed to initialize EGL\n");
75                 goto out;
76         }
77
78         if (!eglChooseConfig(edpy, attr, &ecfg, 1, &num_config)) {
79                 fprintf(stderr, "Failed to choose config (%x)\n", eglGetError());
80                 goto out;
81         }
82
83         if (ecfg == NULL || num_config == 0) {
84                 fprintf(stderr, "No EGL configs available\n");
85                 goto out;
86         }
87
88         esfc = eglCreateWindowSurface(edpy, ecfg,
89                 (EGLNativeWindowType)window, NULL);
90         if (esfc == EGL_NO_SURFACE) {
91                 fprintf(stderr, "Unable to create EGL surface (%x)\n",
92                         eglGetError());
93                 goto out;
94         }
95
96         ectxt = eglCreateContext(edpy, ecfg, EGL_NO_CONTEXT, NULL);
97         if (ectxt == EGL_NO_CONTEXT) {
98                 fprintf(stderr, "Unable to create EGL context (%x)\n",
99                         eglGetError());
100                 goto out;
101         }
102
103         eglMakeCurrent(edpy, esfc, esfc, ectxt);
104
105         glEnable(GL_TEXTURE_2D);
106
107         if (texture_name)
108                 glDeleteTextures(1, &texture_name);
109
110         glGenTextures(1, &texture_name);
111
112         glBindTexture(GL_TEXTURE_2D, texture_name);
113
114         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tex_w, tex_h, 0, GL_RGB,
115                 GL_UNSIGNED_SHORT_5_6_5, tex_mem);
116         if (gl_have_error("glTexImage2D"))
117                 goto out;
118
119         // no mipmaps
120         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
121         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
122
123         //glViewport(0, 0, 512, 512);
124         glLoadIdentity();
125         glFrontFace(GL_CW);
126         glEnable(GL_CULL_FACE);
127
128         glEnableClientState(GL_TEXTURE_COORD_ARRAY);
129         glEnableClientState(GL_VERTEX_ARRAY);
130
131         if (gl_have_error("init"))
132                 goto out;
133
134         gl_es_display = (void *)edpy;
135         gl_es_surface = (void *)esfc;
136         retval = 0;
137 out:
138         return retval;
139 }
140
141 void gl_announce(void)
142 {
143         printf("GL_RENDERER: %s\n", (char *)glGetString(GL_RENDERER));
144 }
145
146 static float vertices[] = {
147         -1.0f,  1.0f,  0.0f, // 0    0  1
148          1.0f,  1.0f,  0.0f, // 1  ^
149         -1.0f, -1.0f,  0.0f, // 2  | 2  3
150          1.0f, -1.0f,  0.0f, // 3  +-->
151 };
152
153 static float texture[] = {
154         0.0f, 0.0f, // we flip this:
155         1.0f, 0.0f, // v^
156         0.0f, 1.0f, //  |  u
157         1.0f, 1.0f, //  +-->
158 };
159
160 int gl_flip(const void *fb, int w, int h)
161 {
162         static int old_w, old_h;
163
164         if (fb != NULL) {
165                 if (w != old_w || h != old_h) {
166                         float f_w = (float)w / tex_w;
167                         float f_h = (float)h / tex_h;
168                         texture[1*2 + 0] = f_w;
169                         texture[2*2 + 1] = f_h;
170                         texture[3*2 + 0] = f_w;
171                         texture[3*2 + 1] = f_h;
172                         old_w = w;
173                         old_h = h;
174                 }
175
176                 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h,
177                         GL_RGB, GL_UNSIGNED_SHORT_5_6_5, fb);
178                 if (gl_have_error("glTexSubImage2D"))
179                         return -1;
180         }
181
182         glVertexPointer(3, GL_FLOAT, 0, vertices);
183         glTexCoordPointer(2, GL_FLOAT, 0, texture);
184         glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
185
186         if (gl_have_error("glDrawArrays"))
187                 return -1;
188
189         eglSwapBuffers(edpy, esfc);
190         if (gles_have_error("eglSwapBuffers"))
191                 return -1;
192
193         return 0;
194 }
195
196 void gl_finish(void)
197 {
198         eglMakeCurrent(edpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
199         eglDestroyContext(edpy, ectxt);
200         ectxt = EGL_NO_CONTEXT;
201         eglDestroySurface(edpy, esfc);
202         esfc = EGL_NO_SURFACE;
203         eglTerminate(edpy);
204         edpy = EGL_NO_DISPLAY;
205
206         gl_es_display = (void *)edpy;
207         gl_es_surface = (void *)esfc;
208
209         if (tex_mem) free(tex_mem);
210         tex_mem = NULL;
211
212         gl_platform_finish();
213 }