#include #include #include #include #include GLuint load_gl_shader_from_sources( GLenum shader_unit, char const * const * const sources, GLint const * const lengths ) { GLuint shader = 0; GLint shader_status = GL_FALSE; char *shader_infolog = NULL; do { size_t n_sources = 0; while( sources[n_sources] ){ ++n_sources; } shader = glCreateShader(shader_unit); if( !shader ){ break; } glShaderSource(shader, n_sources, sources, lengths); glCompileShader(shader); glGetShaderiv(shader, GL_COMPILE_STATUS, &shader_status); if( !shader_status ){ GLint log_length, returned_length; glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_length); shader_infolog = malloc(log_length); if( shader_infolog ){ memset(shader_infolog, 0, log_length); glGetShaderInfoLog( shader, log_length, &returned_length, shader_infolog ); char const * shader_unit_str = NULL; switch(shader_unit) { case GL_VERTEX_SHADER: shader_unit_str = "vertex"; break; case GL_FRAGMENT_SHADER: shader_unit_str = "fragment"; break; } fprintf(stderr, "%s shader compilation failed;\n%*s", shader_unit_str, returned_length, shader_infolog ); } } } while(0); if( !shader_status ){ glDeleteShader(shader); shader = 0; } if( shader_infolog ){ free(shader_infolog); } return shader; } GLuint load_gl_program_from_sources( char const * const * const sources_vs, GLint const * const lengths_vs, char const * const * const sources_fs, GLint const * const lengths_fs ) { GLint linkStatus = GL_FALSE; GLuint program = 0, vert_shader = 0, frag_shader = 0; char const *msg = NULL; do { program = glCreateProgram(); if( !program ){ fprintf(stderr, "glCreateProgram(): %d", glGetError()); break; } if( sources_vs ){ vert_shader = load_gl_shader_from_sources(GL_VERTEX_SHADER, sources_vs, lengths_vs); if( !vert_shader ){ break; } glAttachShader(program, vert_shader); } if( sources_fs ){ frag_shader = load_gl_shader_from_sources(GL_FRAGMENT_SHADER, sources_fs, lengths_fs); if( !frag_shader ){ break; } glAttachShader(program, frag_shader); } glLinkProgram(program); glGetProgramiv(program, GL_LINK_STATUS, &linkStatus); if( !linkStatus ){ GLint log_length, returned_length; glGetProgramiv(program, GL_INFO_LOG_LENGTH, &log_length); char *program_infolog = malloc(log_length); if( program_infolog ){ glGetProgramInfoLog(program, log_length, &returned_length, program_infolog); fprintf(stderr, "shader program linking failed;\n%*s", returned_length, program_infolog ); free(program_infolog); } } } while(0); /* shaders are retained inside the GL context until their last holder, * i.e. the shader program that was just linked is deleted. */ if( vert_shader ){ glDeleteShader(vert_shader); } if( frag_shader ){ glDeleteShader(frag_shader); } if( !linkStatus ){ glDeleteProgram(program); program = 0; } return program; } extern char const _binary_pixels_raw_start; extern char const _binary_pixels_raw_end; #define _binary_pixels_raw ((void const*const)&_binary_pixels_raw_start) #define _binary_pixels_raw_size (size_t)(&_binary_pixels_raw_end - &_binary_pixels_raw_start) #define _binary_pixels_raw_width 1280 #define _binary_pixels_raw_height 960 extern char const _binary_debayer_vs_glsl_end; extern char const _binary_debayer_vs_glsl_start; #define _binary_debayer_vs_glsl ((void const*const)&_binary_debayer_vs_glsl_start) #define _binary_debayer_vs_glsl_size (size_t)(&_binary_debayer_vs_glsl_end - &_binary_debayer_vs_glsl_start) extern char const _binary_debayer_fs_glsl_end; extern char const _binary_debayer_fs_glsl_start; #define _binary_debayer_fs_glsl ((void const*const)&_binary_debayer_fs_glsl_start) #define _binary_debayer_fs_glsl_size (size_t)(&_binary_debayer_fs_glsl_end - &_binary_debayer_fs_glsl_start) static GLenum draw_debayer_RGB(GLuint texture) { #if 1 /* For the moment, just perform 1st degree unity mapping */ GLfloat const coef_r[16] = { 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0. }; GLfloat const *const coef_g = coef_r; GLfloat const *const coef_b = coef_r; /* Those coefficients seem to be way off. Need to investigate further. */ #elif 0 GLfloat const coef_r[16] = { 4.41898209e-01, -1.08617799e-01, -5.05377382e+00, 9.52185120e+00, 2.05420594e+02, -6.17439055e+02, -2.71301881e+03, 1.26291235e+04, 4.06578493e+03, -9.34105168e+04, 1.33991823e+05, 1.27240329e+05, -5.67983982e+05, 6.77352564e+05, -3.70453281e+05, 7.96913561e+04 }; GLfloat const coef_g[16] = { 1.75630153e-01, 1.77970251e-01, 3.93921859e+00, -3.83900750e+01, -8.50868580e+01, 1.39497351e+03, -1.50332837e+03, -1.85003596e+04, 6.53562460e+04, -1.00909757e+04, -3.92586418e+05, 1.06909568e+06, -1.42125035e+06, 1.07029531e+06, -4.38315295e+05, 7.62246706e+04 }; GLfloat const coef_b[16] = { 2.44126153e-01, 1.71659546e-01, 5.35993954e-01, -8.10729044e+00, -7.11102399e+00, 1.24421866e+02, 1.22255723e-02, -8.74245656e+02, 4.72294698e+02, 2.99248407e+03, -2.85191269e+03, -4.54081854e+03, 6.46045466e+03, 1.41007972e+03, -5.12551110e+03, 1.94825904e+03 }; #else GLfloat const coef_r[16] = { 2.43242336e+00, 1.29527225e+01, -1.67053874e+02, -1.03264624e+03, 3.89533658e+04, -3.79431617e+05, 2.04443576e+06, -7.12156509e+06, 1.71198465e+07, -2.92874193e+07, 3.60398126e+07, -3.17297224e+07, 1.95237028e+07, -7.98040387e+06, 1.94790465e+06, -2.14928147e+05 }; GLfloat const coef_g[16] = { 5.24353947e+00, 2.96584994e+01, -1.73865606e+02, -1.93045987e+03, 1.85513793e+04, -4.48754651e+04, -1.32006487e+05, 1.24471739e+06, -4.25234811e+06, 8.83297659e+06, -1.23501912e+07, 1.19377860e+07, -7.90632536e+06, 3.43589308e+06, -8.84463954e+05, 1.02356618e+05 }; GLfloat const coef_b[16] = { 4.04493164e+00, -1.46245348e+01, 1.71095269e+02, 2.06498987e+03, -4.93803069e+04, 3.95481675e+05, -1.82105431e+06, 5.53531911e+06, -1.17786850e+07, 1.80202854e+07, -1.99760831e+07, 1.59213215e+07, -8.89476364e+06, 3.30494584e+06, -7.32930586e+05, 7.33188936e+04 }; #endif static GLuint prog = 0, a_position, u_sampler, u_coef_r, u_coef_g, u_coef_b; if( !prog ){ char const *src_vs[] = { _binary_debayer_vs_glsl, NULL }; GLint const sz_vs[] = { _binary_debayer_vs_glsl_size, 0 }; char const *src_fs[] = { _binary_debayer_fs_glsl, NULL }; GLint const sz_fs[] = { _binary_debayer_fs_glsl_size, 0 }; prog = load_gl_program_from_sources(src_vs, sz_vs, src_fs, sz_fs); if( !prog ){ _Exit(1); return GL_INVALID_VALUE; } a_position = glGetAttribLocation(prog, "a_position"); u_sampler = glGetUniformLocation(prog, "u_sampler"); u_coef_r = glGetUniformLocation(prog, "u_coef_r"); u_coef_g = glGetUniformLocation(prog, "u_coef_g"); u_coef_b = glGetUniformLocation(prog, "u_coef_b"); } static GLuint vbo_xy = 0; if( !vbo_xy ){ // a triangle that fully covers the rectangle // ((0,0),(1,1)) in counter clock vertex order. GLfloat const data[] = { 0.0, 0.0, 2.0, 0.0, 0.0, 2.0 }; glGenBuffers(1, &vbo_xy); if( !vbo_xy ){ return glGetError(); } glBindBuffer(GL_ARRAY_BUFFER, vbo_xy); glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); } static GLuint tex; if( !tex ){ glGenTextures(1, &tex); if( !tex ){ return glGetError(); } glBindTexture(GL_TEXTURE_2D, tex); if( !(_binary_pixels_raw_width % 4) ){ glPixelStorei(GL_UNPACK_ALIGNMENT, 4); } else if( !(_binary_pixels_raw_width % 2) ){ glPixelStorei(GL_UNPACK_ALIGNMENT, 2); } else { glPixelStorei(GL_UNPACK_ALIGNMENT, 1); } /* when loading the pixels into the texture, each two consecutive * primitive pixels are coalesced into a single 2-channel texel. * Furthermore, since primitives order are distinct between * even and odd rows, a texture half the primitive height is created * but at the primitive picture width. Hence we will end up a * texture that contains two pictures side by side, even rows * on the left and odd rows on the right. Since the subpictures * have uniform primitives arrangement each, we can use built-in * mipmap generation to downsample the picture for mipmapping * without impeding the de-Bayering process. */ glTexImage2D( /* target = */ GL_TEXTURE_2D, /* level = */ 0, /* The 2 component image format of OpenGL-ES 2 * is GL_LUMINANCE_ALPHA; on later versions you'd * use GL_RG; internalformat = */ GL_LUMINANCE_ALPHA, /* width = */ _binary_pixels_raw_width, /* height = */ _binary_pixels_raw_height/2, /* border = */ 0, /* format = */ GL_LUMINANCE_ALPHA, /* type = */ GL_UNSIGNED_BYTE, /* data = */ _binary_pixels_raw ); glGenerateMipmap(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, 0); } glUseProgram(prog); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, tex); glUniform1i(u_sampler, 0); glUniformMatrix4fv(u_coef_r, 1, GL_FALSE, coef_r); glUniformMatrix4fv(u_coef_g, 1, GL_FALSE, coef_g); glUniformMatrix4fv(u_coef_b, 1, GL_FALSE, coef_b); glBindBuffer(GL_ARRAY_BUFFER, vbo_xy); glEnableVertexAttribArray(a_position); glVertexAttribPointer(a_position, 2, GL_FLOAT, GL_FALSE, 0, NULL); glDrawArrays(GL_TRIANGLES, 0, 3); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindTexture(GL_TEXTURE_2D, 0); glUseProgram(0); return glGetError(); } int main() { int screenwidth = _binary_pixels_raw_width; int screenheight = _binary_pixels_raw_height; EGLint numConfigs, majorVersion, minorVersion; SDL_Window *window = SDL_CreateWindow( "GLESv2 / fragment shader de-Bayer", 0, 0, screenwidth, screenheight, SDL_WINDOW_OPENGL); EGLConfig config = {0}; EGLint const egl_config_attr[] = { EGL_BUFFER_SIZE, 24, EGL_DEPTH_SIZE, 24, EGL_STENCIL_SIZE, 8, EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_NONE }; EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); eglInitialize(display, &majorVersion, &minorVersion); eglChooseConfig(display, egl_config_attr, &config, 1, &numConfigs); SDL_SysWMinfo sysInfo; SDL_VERSION(&sysInfo.version); SDL_GetWindowWMInfo(window, &sysInfo); EGLint const egl_context_attr[] = { EGL_CONTEXT_MAJOR_VERSION, 2, EGL_NONE }; EGLContext context = eglCreateContext(display, config, EGL_NO_CONTEXT, egl_context_attr); EGLSurface surface = eglCreateWindowSurface(display, config, (EGLNativeWindowType)sysInfo.info.x11.window, 0); // X11? eglMakeCurrent(display, surface, surface, context); eglSwapInterval(display, 1); for( SDL_Event event = {0} ; SDL_QUIT != event.type ; SDL_PollEvent(&event) ){ glViewport(0, 0, screenwidth, screenheight); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); draw_debayer_RGB(0); eglSwapBuffers(display, surface); } eglDestroySurface(display, surface); eglDestroyContext(display, context); eglTerminate(display); SDL_DestroyWindow(window); return 0; }