raspberry pi port
[gpsp.git] / raspberrypi / gles_video.c
1 #include "bcm_host.h"
2 #include "GLES/gl.h"
3 #include "EGL/egl.h"
4 #include "EGL/eglext.h"
5 #include "GLES2/gl2.h"
6 #include <assert.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <memory.h>
10
11 static uint32_t frame_width = 0;
12 static uint32_t frame_height = 0;
13
14
15 #define SHOW_ERROR              gles_show_error();
16
17 static void SetOrtho(GLfloat m[4][4], GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat near, GLfloat far, GLfloat scale_x, GLfloat scale_y);
18
19 static const char* vertex_shader =
20         "uniform mat4 u_vp_matrix;                                                              \n"
21         "attribute vec4 a_position;                                                             \n"
22         "attribute vec2 a_texcoord;                                                             \n"
23         "varying mediump vec2 v_texcoord;                                               \n"
24         "void main()                                                                                    \n"
25         "{                                                                                                              \n"
26         "       v_texcoord = a_texcoord;                                                        \n"
27         "       gl_Position = u_vp_matrix * a_position;                         \n"
28         "}                                                                                                              \n";
29
30 static const char* fragment_shader =
31         "varying mediump vec2 v_texcoord;                                               \n"
32         "uniform sampler2D u_texture;                                                   \n"
33         "void main()                                                                                    \n"
34         "{                                                                                                              \n"
35         "       gl_FragColor = texture2D(u_texture, v_texcoord);        \n"
36         "}                                                                                                              \n";
37 /*
38 static const GLfloat vertices[] =
39 {
40         -0.5f, -0.5f, 0.0f,
41         +0.5f, -0.5f, 0.0f,
42         +0.5f, +0.5f, 0.0f,
43         -0.5f, +0.5f, 0.0f,
44 };
45 */
46 static const GLfloat vertices[] =
47 {
48         -0.5f, -0.5f, 0.0f,
49         -0.5f, +0.5f, 0.0f,
50         +0.5f, +0.5f, 0.0f,
51         +0.5f, -0.5f, 0.0f,
52 };
53
54 #define TEX_WIDTH       1024
55 #define TEX_HEIGHT      512
56
57 static const GLfloat uvs[8];
58
59 static const GLushort indices[] =
60 {
61         0, 1, 2,
62         0, 2, 3,
63 };
64
65 static const int kVertexCount = 4;
66 static const int kIndexCount = 6;
67
68
69 void Create_uvs(GLfloat * matrix, GLfloat max_u, GLfloat max_v) {
70     memset(matrix,0,sizeof(GLfloat)*8);
71     matrix[3]=max_v;
72     matrix[4]=max_u;
73     matrix[5]=max_v;
74     matrix[6]=max_u;
75
76 }
77
78 void gles_show_error()
79 {
80         GLenum error = GL_NO_ERROR;
81     error = glGetError();
82     if (GL_NO_ERROR != error)
83         printf("GL Error %x encountered!\n", error);
84 }
85
86 static GLuint CreateShader(GLenum type, const char *shader_src)
87 {
88         GLuint shader = glCreateShader(type);
89         if(!shader)
90                 return 0;
91
92         // Load and compile the shader source
93         glShaderSource(shader, 1, &shader_src, NULL);
94         glCompileShader(shader);
95
96         // Check the compile status
97         GLint compiled = 0;
98         glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
99         if(!compiled)
100         {
101                 GLint info_len = 0;
102                 glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &info_len);
103                 if(info_len > 1)
104                 {
105                         char* info_log = (char *)malloc(sizeof(char) * info_len);
106                         glGetShaderInfoLog(shader, info_len, NULL, info_log);
107                         // TODO(dspringer): We could really use a logging API.
108                         printf("Error compiling shader:\n%s\n", info_log);
109                         free(info_log);
110                 }
111                 glDeleteShader(shader);
112                 return 0;
113         }
114         return shader;
115 }
116
117 static GLuint CreateProgram(const char *vertex_shader_src, const char *fragment_shader_src)
118 {
119         GLuint vertex_shader = CreateShader(GL_VERTEX_SHADER, vertex_shader_src);
120         if(!vertex_shader)
121                 return 0;
122         GLuint fragment_shader = CreateShader(GL_FRAGMENT_SHADER, fragment_shader_src);
123         if(!fragment_shader)
124         {
125                 glDeleteShader(vertex_shader);
126                 return 0;
127         }
128
129         GLuint program_object = glCreateProgram();
130         if(!program_object)
131                 return 0;
132         glAttachShader(program_object, vertex_shader);
133         glAttachShader(program_object, fragment_shader);
134
135         // Link the program
136         glLinkProgram(program_object);
137
138         // Check the link status
139         GLint linked = 0;
140         glGetProgramiv(program_object, GL_LINK_STATUS, &linked);
141         if(!linked)
142         {
143                 GLint info_len = 0;
144                 glGetProgramiv(program_object, GL_INFO_LOG_LENGTH, &info_len);
145                 if(info_len > 1)
146                 {
147                         char* info_log = (char *)malloc(info_len);
148                         glGetProgramInfoLog(program_object, info_len, NULL, info_log);
149                         // TODO(dspringer): We could really use a logging API.
150                         printf("Error linking program:\n%s\n", info_log);
151                         free(info_log);
152                 }
153                 glDeleteProgram(program_object);
154                 return 0;
155         }
156         // Delete these here because they are attached to the program object.
157         glDeleteShader(vertex_shader);
158         glDeleteShader(fragment_shader);
159         return program_object;
160 }
161
162 typedef struct ShaderInfo {
163                 GLuint program;
164                 GLint a_position;
165                 GLint a_texcoord;
166                 GLint u_vp_matrix;
167                 GLint u_texture;
168 } ShaderInfo;
169
170 static ShaderInfo shader;
171 static ShaderInfo shader_filtering;
172 static GLuint buffers[3];
173 static GLuint textures[2];
174
175
176 static void gles2_create()
177 {
178         memset(&shader, 0, sizeof(ShaderInfo));
179         shader.program = CreateProgram(vertex_shader, fragment_shader);
180         if(shader.program)
181         {
182                 shader.a_position       = glGetAttribLocation(shader.program,   "a_position");
183                 shader.a_texcoord       = glGetAttribLocation(shader.program,   "a_texcoord");
184                 shader.u_vp_matrix      = glGetUniformLocation(shader.program,  "u_vp_matrix");
185                 shader.u_texture        = glGetUniformLocation(shader.program,  "u_texture");
186         }
187         glGenTextures(1, textures);
188         glBindTexture(GL_TEXTURE_2D, textures[0]);
189         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, TEX_WIDTH, TEX_HEIGHT, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, NULL);
190
191         Create_uvs(uvs, (float)frame_width/TEX_WIDTH, (float)frame_height/TEX_HEIGHT);
192
193         glGenBuffers(3, buffers);
194         glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
195         glBufferData(GL_ARRAY_BUFFER, kVertexCount * sizeof(GLfloat) * 3, vertices, GL_STATIC_DRAW);
196         glBindBuffer(GL_ARRAY_BUFFER, buffers[1]);
197         glBufferData(GL_ARRAY_BUFFER, kVertexCount * sizeof(GLfloat) * 2, uvs, GL_STATIC_DRAW);
198         glBindBuffer(GL_ARRAY_BUFFER, 0);
199         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[2]);
200         glBufferData(GL_ELEMENT_ARRAY_BUFFER, kIndexCount * sizeof(GL_UNSIGNED_SHORT), indices, GL_STATIC_DRAW);
201         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
202
203         glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
204         glDisable(GL_DEPTH_TEST);
205         glDisable(GL_BLEND);
206         glDisable(GL_DITHER);
207 }
208
209 static uint32_t screen_width = 0;
210 static uint32_t screen_height = 0;
211
212 static EGLDisplay display = NULL;
213 static EGLSurface surface = NULL;
214 static EGLContext context = NULL;
215 static EGL_DISPMANX_WINDOW_T nativewindow;
216
217 static GLfloat proj[4][4];
218 static GLint filter_min;
219 static GLint filter_mag;
220
221 void video_set_filter(uint32_t filter) {
222         if (filter==0) {
223             filter_min = GL_NEAREST;
224             filter_mag = GL_NEAREST;
225         } else  {
226             filter_min = GL_LINEAR;
227             filter_mag = GL_LINEAR;
228         }
229 }
230
231 void video_init(uint32_t _width, uint32_t _height, uint32_t filter)
232 {
233         if ((_width==0)||(_height==0))
234                 return;
235
236         frame_width = _width;
237         frame_height = _height;
238         
239         //bcm_host_init();
240
241         // get an EGL display connection
242         display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
243         assert(display != EGL_NO_DISPLAY);
244
245         // initialize the EGL display connection
246         EGLBoolean result = eglInitialize(display, NULL, NULL);
247         assert(EGL_FALSE != result);
248
249         // get an appropriate EGL frame buffer configuration
250         EGLint num_config;
251         EGLConfig config;
252         static const EGLint attribute_list[] =
253         {
254                 EGL_RED_SIZE, 8,
255                 EGL_GREEN_SIZE, 8,
256                 EGL_BLUE_SIZE, 8,
257                 EGL_ALPHA_SIZE, 8,
258                 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
259                 EGL_NONE
260         };
261         result = eglChooseConfig(display, attribute_list, &config, 1, &num_config);
262         assert(EGL_FALSE != result);
263
264         result = eglBindAPI(EGL_OPENGL_ES_API);
265         assert(EGL_FALSE != result);
266
267         // create an EGL rendering context
268         static const EGLint context_attributes[] =
269         {
270                 EGL_CONTEXT_CLIENT_VERSION, 2,
271                 EGL_NONE
272         };
273         context = eglCreateContext(display, config, EGL_NO_CONTEXT, context_attributes);
274         assert(context != EGL_NO_CONTEXT);
275
276         // create an EGL window surface
277         int32_t success = graphics_get_display_size(0, &screen_width, &screen_height);
278         assert(success >= 0);
279
280         VC_RECT_T dst_rect;
281         dst_rect.x = 0;
282         dst_rect.y = 0;
283         dst_rect.width = screen_width;
284         dst_rect.height = screen_height;
285
286         VC_RECT_T src_rect;
287         src_rect.x = 0;
288         src_rect.y = 0;
289         src_rect.width = screen_width << 16;
290         src_rect.height = screen_height << 16;
291
292         DISPMANX_DISPLAY_HANDLE_T dispman_display = vc_dispmanx_display_open(0);
293         DISPMANX_UPDATE_HANDLE_T dispman_update = vc_dispmanx_update_start(0);
294         DISPMANX_ELEMENT_HANDLE_T dispman_element = vc_dispmanx_element_add(dispman_update, dispman_display,
295          1, &dst_rect, 0, &src_rect, DISPMANX_PROTECTION_NONE, NULL, NULL, DISPMANX_NO_ROTATE);
296
297         nativewindow.element = dispman_element;
298         nativewindow.width = screen_width;
299         nativewindow.height = screen_height;
300         vc_dispmanx_update_submit_sync(dispman_update);
301
302         surface = eglCreateWindowSurface(display, config, &nativewindow, NULL);
303         assert(surface != EGL_NO_SURFACE);
304
305         // connect the context to the surface
306         result = eglMakeCurrent(display, surface, surface, context);
307         assert(EGL_FALSE != result);
308
309         gles2_create();
310
311         int r=(screen_height*10/frame_height);
312         int h = (frame_height*r)/10;
313         int w = (frame_width*r)/10;
314         if (w>screen_width) {
315             r = (screen_width*10/frame_width);
316             h = (frame_height*r)/10;
317             w = (frame_width*r)/10;
318         }
319         glViewport((screen_width-w)/2, (screen_height-h)/2, w, h);
320         SetOrtho(proj, -0.5f, +0.5f, +0.5f, -0.5f, -1.0f, 1.0f, 1.0f ,1.0f );
321         video_set_filter(filter);
322 }
323
324 static void gles2_destroy()
325 {
326         if(!shader.program)
327                 return;
328         glDeleteBuffers(3, buffers); SHOW_ERROR
329         glDeleteProgram(shader.program); SHOW_ERROR
330 }
331
332 static void SetOrtho(GLfloat m[4][4], GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat near, GLfloat far, GLfloat scale_x, GLfloat scale_y)
333 {
334         memset(m, 0, 4*4*sizeof(GLfloat));
335         m[0][0] = 2.0f/(right - left)*scale_x;
336         m[1][1] = 2.0f/(top - bottom)*scale_y;
337         m[2][2] = -2.0f/(far - near);
338         m[3][0] = -(right + left)/(right - left);
339         m[3][1] = -(top + bottom)/(top - bottom);
340         m[3][2] = -(far + near)/(far - near);
341         m[3][3] = 1;
342 }
343 #define RGB15(r, g, b)  (((r) << (5+6)) | ((g) << 6) | (b))
344
345 static void gles2_Draw( uint16_t *pixels)
346 {
347         if(!shader.program)
348                 return;
349
350         glClear(GL_COLOR_BUFFER_BIT);
351
352         glUseProgram(shader.program);
353
354         glBindTexture(GL_TEXTURE_2D, textures[0]);
355         glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, frame_width, frame_height, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, pixels);
356         glActiveTexture(GL_TEXTURE0);
357         glUniform1i(shader.u_texture, 0);
358         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter_mag);
359         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter_min);
360         glGenerateMipmap(GL_TEXTURE_2D);
361
362         glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
363         glVertexAttribPointer(shader.a_position, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), NULL);
364         glEnableVertexAttribArray(shader.a_position);
365
366         glBindBuffer(GL_ARRAY_BUFFER, buffers[1]);
367         glVertexAttribPointer(shader.a_texcoord, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), NULL);
368         glEnableVertexAttribArray(shader.a_texcoord);
369
370         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[2]);
371         glUniformMatrix4fv(shader.u_vp_matrix, 1, GL_FALSE, (const GLfloat * )&proj);
372         glDrawElements(GL_TRIANGLES, kIndexCount, GL_UNSIGNED_SHORT, 0);
373
374         glBindBuffer(GL_ARRAY_BUFFER, 0);
375         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
376         //glFlush();
377 }
378
379 void video_close()
380 {
381         gles2_destroy();
382         // Release OpenGL resources
383         eglMakeCurrent( display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );
384         eglDestroySurface( display, surface );
385         eglDestroyContext( display, context );
386         eglTerminate( display );
387 }
388
389 void video_draw(uint16_t *pixels)
390 {
391         gles2_Draw (pixels);
392         eglSwapBuffers(display, surface);
393 }