diff options
Diffstat (limited to 'raspberrypi/test/gles_video.c')
-rw-r--r-- | raspberrypi/test/gles_video.c | 383 |
1 files changed, 383 insertions, 0 deletions
diff --git a/raspberrypi/test/gles_video.c b/raspberrypi/test/gles_video.c new file mode 100644 index 0000000..4d7d405 --- /dev/null +++ b/raspberrypi/test/gles_video.c @@ -0,0 +1,383 @@ +#include "bcm_host.h" +#include "GLES/gl.h" +#include "EGL/egl.h" +#include "EGL/eglext.h" +#include "GLES2/gl2.h" +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <memory.h> + +static uint32_t frame_width = 0; +static uint32_t frame_height = 0; + + +#define SHOW_ERROR gles_show_error(); + +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); + +static const char* vertex_shader = + "uniform mat4 u_vp_matrix; \n" + "attribute vec4 a_position; \n" + "attribute vec2 a_texcoord; \n" + "varying mediump vec2 v_texcoord; \n" + "void main() \n" + "{ \n" + " v_texcoord = a_texcoord; \n" + " gl_Position = u_vp_matrix * a_position; \n" + "} \n"; + +static const char* fragment_shader = + "varying mediump vec2 v_texcoord; \n" + "uniform sampler2D u_texture; \n" + "void main() \n" + "{ \n" + " gl_FragColor = texture2D(u_texture, v_texcoord); \n" + "} \n"; + +static const GLfloat vertices[] = +{ + -0.5f, -0.5f, 0.0f, + +0.5f, -0.5f, 0.0f, + +0.5f, +0.5f, 0.0f, + -0.5f, +0.5f, 0.0f, +}; + +#define TEX_WIDTH 1024 +#define TEX_HEIGHT 512 + +static const GLfloat uvs[8]; + +static const GLushort indices[] = +{ + 0, 1, 2, + 0, 2, 3, +}; + +static const int kVertexCount = 4; +static const int kIndexCount = 6; + + +void Create_uvs(GLfloat * matrix, GLfloat max_u, GLfloat max_v) { + memset(matrix,0,sizeof(GLfloat)*8); + matrix[3]=max_v; + matrix[4]=max_u; + matrix[5]=max_v; + matrix[6]=max_u; + +} + +void gles_show_error() +{ + GLenum error = GL_NO_ERROR; + error = glGetError(); + if (GL_NO_ERROR != error) + printf("GL Error %x encountered!\n", error); +} + +static GLuint CreateShader(GLenum type, const char *shader_src) +{ + GLuint shader = glCreateShader(type); + if(!shader) + return 0; + + // Load and compile the shader source + glShaderSource(shader, 1, &shader_src, NULL); + glCompileShader(shader); + + // Check the compile status + GLint compiled = 0; + glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled); + if(!compiled) + { + GLint info_len = 0; + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &info_len); + if(info_len > 1) + { + char* info_log = (char *)malloc(sizeof(char) * info_len); + glGetShaderInfoLog(shader, info_len, NULL, info_log); + // TODO(dspringer): We could really use a logging API. + printf("Error compiling shader:\n%s\n", info_log); + free(info_log); + } + glDeleteShader(shader); + return 0; + } + return shader; +} + +static GLuint CreateProgram(const char *vertex_shader_src, const char *fragment_shader_src) +{ + GLuint vertex_shader = CreateShader(GL_VERTEX_SHADER, vertex_shader_src); + if(!vertex_shader) + return 0; + GLuint fragment_shader = CreateShader(GL_FRAGMENT_SHADER, fragment_shader_src); + if(!fragment_shader) + { + glDeleteShader(vertex_shader); + return 0; + } + + GLuint program_object = glCreateProgram(); + if(!program_object) + return 0; + glAttachShader(program_object, vertex_shader); + glAttachShader(program_object, fragment_shader); + + // Link the program + glLinkProgram(program_object); + + // Check the link status + GLint linked = 0; + glGetProgramiv(program_object, GL_LINK_STATUS, &linked); + if(!linked) + { + GLint info_len = 0; + glGetProgramiv(program_object, GL_INFO_LOG_LENGTH, &info_len); + if(info_len > 1) + { + char* info_log = (char *)malloc(info_len); + glGetProgramInfoLog(program_object, info_len, NULL, info_log); + // TODO(dspringer): We could really use a logging API. + printf("Error linking program:\n%s\n", info_log); + free(info_log); + } + glDeleteProgram(program_object); + return 0; + } + // Delete these here because they are attached to the program object. + glDeleteShader(vertex_shader); + glDeleteShader(fragment_shader); + return program_object; +} + +typedef struct ShaderInfo { + GLuint program; + GLint a_position; + GLint a_texcoord; + GLint u_vp_matrix; + GLint u_texture; +} ShaderInfo; + +static ShaderInfo shader; +static ShaderInfo shader_filtering; +static GLuint buffers[3]; +static GLuint textures[2]; + + +static void gles2_create() +{ + memset(&shader, 0, sizeof(ShaderInfo)); + shader.program = CreateProgram(vertex_shader, fragment_shader); + if(shader.program) + { + shader.a_position = glGetAttribLocation(shader.program, "a_position"); + shader.a_texcoord = glGetAttribLocation(shader.program, "a_texcoord"); + shader.u_vp_matrix = glGetUniformLocation(shader.program, "u_vp_matrix"); + shader.u_texture = glGetUniformLocation(shader.program, "u_texture"); + } + glGenTextures(1, textures); + glBindTexture(GL_TEXTURE_2D, textures[0]); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, TEX_WIDTH, TEX_HEIGHT, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, NULL); + + Create_uvs(uvs, (float)frame_width/TEX_WIDTH, (float)frame_height/TEX_HEIGHT); + + glGenBuffers(3, buffers); + glBindBuffer(GL_ARRAY_BUFFER, buffers[0]); + glBufferData(GL_ARRAY_BUFFER, kVertexCount * sizeof(GLfloat) * 3, vertices, GL_STATIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, buffers[1]); + glBufferData(GL_ARRAY_BUFFER, kVertexCount * sizeof(GLfloat) * 2, uvs, GL_STATIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[2]); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, kIndexCount * sizeof(GL_UNSIGNED_SHORT), indices, GL_STATIC_DRAW); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + glDisable(GL_DEPTH_TEST); + glDisable(GL_BLEND); + glDisable(GL_DITHER); +} + +static uint32_t screen_width = 0; +static uint32_t screen_height = 0; + +static EGLDisplay display = NULL; +static EGLSurface surface = NULL; +static EGLContext context = NULL; +static EGL_DISPMANX_WINDOW_T nativewindow; + +static GLfloat proj[4][4]; +static GLint filter_min; +static GLint filter_mag; + +void video_init(uint32_t _width, uint32_t _height, uint32_t filter) +{ + if ((_width==0)||(_height==0)) + return; + + frame_width = _width; + frame_height = _height; + + bcm_host_init(); + + // get an EGL display connection + display = eglGetDisplay(EGL_DEFAULT_DISPLAY); + assert(display != EGL_NO_DISPLAY); + + // initialize the EGL display connection + EGLBoolean result = eglInitialize(display, NULL, NULL); + assert(EGL_FALSE != result); + + // get an appropriate EGL frame buffer configuration + EGLint num_config; + EGLConfig config; + static const EGLint attribute_list[] = + { + EGL_RED_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_BLUE_SIZE, 8, + EGL_ALPHA_SIZE, 8, + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + EGL_NONE + }; + result = eglChooseConfig(display, attribute_list, &config, 1, &num_config); + assert(EGL_FALSE != result); + + result = eglBindAPI(EGL_OPENGL_ES_API); + assert(EGL_FALSE != result); + + // create an EGL rendering context + static const EGLint context_attributes[] = + { + EGL_CONTEXT_CLIENT_VERSION, 2, + EGL_NONE + }; + context = eglCreateContext(display, config, EGL_NO_CONTEXT, context_attributes); + assert(context != EGL_NO_CONTEXT); + + // create an EGL window surface + int32_t success = graphics_get_display_size(0, &screen_width, &screen_height); + assert(success >= 0); + + VC_RECT_T dst_rect; + dst_rect.x = 0; + dst_rect.y = 0; + dst_rect.width = screen_width; + dst_rect.height = screen_height; + + VC_RECT_T src_rect; + src_rect.x = 0; + src_rect.y = 0; + src_rect.width = screen_width << 16; + src_rect.height = screen_height << 16; + + DISPMANX_DISPLAY_HANDLE_T dispman_display = vc_dispmanx_display_open(0); + DISPMANX_UPDATE_HANDLE_T dispman_update = vc_dispmanx_update_start(0); + DISPMANX_ELEMENT_HANDLE_T dispman_element = vc_dispmanx_element_add(dispman_update, dispman_display, + 0, &dst_rect, 0, &src_rect, DISPMANX_PROTECTION_NONE, NULL, NULL, DISPMANX_NO_ROTATE); + + nativewindow.element = dispman_element; + nativewindow.width = screen_width; + nativewindow.height = screen_height; + vc_dispmanx_update_submit_sync(dispman_update); + + surface = eglCreateWindowSurface(display, config, &nativewindow, NULL); + assert(surface != EGL_NO_SURFACE); + + // connect the context to the surface + result = eglMakeCurrent(display, surface, surface, context); + assert(EGL_FALSE != result); + + gles2_create(); + + int r=(screen_height*10/frame_height); + int h = (frame_height*r)/10; + int w = (frame_width*r)/10; + + glViewport((screen_width-w)/2, (screen_height-h)/2, w, h); + SetOrtho(proj, -0.5f, +0.5f, +0.5f, -0.5f, -1.0f, 1.0f, 1.0f ,1.0f ); + if (filter==0) { + filter_min = GL_NEAREST; + filter_mag = GL_NEAREST; + } else if (filter==1) { + filter_min = GL_LINEAR_MIPMAP_LINEAR; + filter_mag = GL_LINEAR; + } else if (filter==2) { + filter_min = GL_LINEAR_MIPMAP_NEAREST; + filter_mag = GL_LINEAR; + + } + +} + +static void gles2_destroy() +{ + if(!shader.program) + return; + glDeleteBuffers(3, buffers); SHOW_ERROR + glDeleteProgram(shader.program); SHOW_ERROR +} + +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) +{ + memset(m, 0, 4*4*sizeof(GLfloat)); + m[0][0] = 2.0f/(right - left)*scale_x; + m[1][1] = 2.0f/(top - bottom)*scale_y; + m[2][2] = -2.0f/(far - near); + m[3][0] = -(right + left)/(right - left); + m[3][1] = -(top + bottom)/(top - bottom); + m[3][2] = -(far + near)/(far - near); + m[3][3] = 1; +} +#define RGB15(r, g, b) (((r) << (5+6)) | ((g) << 6) | (b)) + +static void gles2_Draw( uint16_t *pixels) +{ + if(!shader.program) + return; + + glClear(GL_COLOR_BUFFER_BIT); + + glUseProgram(shader.program); + + glBindTexture(GL_TEXTURE_2D, textures[0]); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, frame_width, frame_height, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, pixels); + glActiveTexture(GL_TEXTURE0); + glUniform1i(shader.u_texture, 0); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter_min); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter_mag); + glGenerateMipmap(GL_TEXTURE_2D); + + glBindBuffer(GL_ARRAY_BUFFER, buffers[0]); + glVertexAttribPointer(shader.a_position, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), NULL); + glEnableVertexAttribArray(shader.a_position); + + glBindBuffer(GL_ARRAY_BUFFER, buffers[1]); + glVertexAttribPointer(shader.a_texcoord, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), NULL); + glEnableVertexAttribArray(shader.a_texcoord); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[2]); + glUniformMatrix4fv(shader.u_vp_matrix, 1, GL_FALSE, (const GLfloat * )&proj); + glDrawElements(GL_TRIANGLES, kIndexCount, GL_UNSIGNED_SHORT, 0); + + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + //glFlush(); +} + +void video_close() +{ + gles2_destroy(); + // Release OpenGL resources + eglMakeCurrent( display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT ); + eglDestroySurface( display, surface ); + eglDestroyContext( display, context ); + eglTerminate( display ); +} + +void video_draw(uint16_t *pixels) +{ + gles2_Draw (pixels); + eglSwapBuffers(display, surface); +} |