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