raspberry pi port
[gpsp.git] / raspberrypi / gles_video.c
CommitLineData
ffa573f8
D
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
11static uint32_t frame_width = 0;
12static uint32_t frame_height = 0;
13
14
15#define SHOW_ERROR gles_show_error();
16
17static 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
19static 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
30static 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/*
38static 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*/
46static 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
57static const GLfloat uvs[8];
58
59static const GLushort indices[] =
60{
61 0, 1, 2,
62 0, 2, 3,
63};
64
65static const int kVertexCount = 4;
66static const int kIndexCount = 6;
67
68
69void 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
78void 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
86static 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
117static 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
162typedef 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
170static ShaderInfo shader;
171static ShaderInfo shader_filtering;
172static GLuint buffers[3];
173static GLuint textures[2];
174
175
176static 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
209static uint32_t screen_width = 0;
210static uint32_t screen_height = 0;
211
212static EGLDisplay display = NULL;
213static EGLSurface surface = NULL;
214static EGLContext context = NULL;
215static EGL_DISPMANX_WINDOW_T nativewindow;
216
217static GLfloat proj[4][4];
218static GLint filter_min;
219static GLint filter_mag;
220
221void 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
231void 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
324static void gles2_destroy()
325{
326 if(!shader.program)
327 return;
328 glDeleteBuffers(3, buffers); SHOW_ERROR
329 glDeleteProgram(shader.program); SHOW_ERROR
330}
331
332static 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
345static 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
379void 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
389void video_draw(uint16_t *pixels)
390{
391 gles2_Draw (pixels);
392 eglSwapBuffers(display, surface);
393}