diff --git a/data/debayer.frag b/data/debayer.frag index d0900e3..a8f4a36 100644 --- a/data/debayer.frag +++ b/data/debayer.frag @@ -20,49 +20,49 @@ varying vec2 bottom_right_uv; vec2 skip_5th_pixel(vec2 uv) { - vec2 new_uv = uv; + vec2 new_uv = uv; - new_uv.x *= 0.8; - new_uv.x += floor(uv.x * row_length / 5.0) / row_length; + new_uv.x *= 0.8; + new_uv.x += floor(uv.x * row_length / 5.0) / row_length; - // Crop out padding - new_uv.x *= padding_ratio; + // Crop out padding + new_uv.x *= padding_ratio; - return new_uv; + return new_uv; } #endif void main() { - // Note the coordinates for texture samples need to be a varying, as the - // Mali-400 has this as a fast path allowing 32-bit floats. Otherwise - // they end up as 16-bit floats and that's not accurate enough. -#ifdef BITS_10 - vec4 samples = vec4(texture2D(texture, skip_5th_pixel(top_left_uv)).r, - texture2D(texture, skip_5th_pixel(top_right_uv)).r, - texture2D(texture, skip_5th_pixel(bottom_left_uv)).r, - texture2D(texture, skip_5th_pixel(bottom_right_uv)).r); -#else - vec4 samples = vec4(texture2D(texture, top_left_uv).r, - texture2D(texture, top_right_uv).r, - texture2D(texture, bottom_left_uv).r, - texture2D(texture, bottom_right_uv).r); -#endif + // Note the coordinates for texture samples need to be a varying, as the + // Mali-400 has this as a fast path allowing 32-bit floats. Otherwise + // they end up as 16-bit floats and that's not accurate enough. + #ifdef BITS_10 + vec4 samples = vec4(texture2D(texture, skip_5th_pixel(top_left_uv)).r, + texture2D(texture, skip_5th_pixel(top_right_uv)).r, + texture2D(texture, skip_5th_pixel(bottom_left_uv)).r, + texture2D(texture, skip_5th_pixel(bottom_right_uv)).r); + #else + vec4 samples = vec4(texture2D(texture, top_left_uv).r, + texture2D(texture, top_right_uv).r, + texture2D(texture, bottom_left_uv).r, + texture2D(texture, bottom_right_uv).r); + #endif -#if defined(CFA_BGGR) - vec3 color = vec3(samples.w, (samples.y + samples.z) / 2.0, samples.x); -#elif defined(CFA_GBRG) - vec3 color = vec3(samples.z, (samples.x + samples.w) / 2.0, samples.y); -#elif defined(CFA_GRBG) - vec3 color = vec3(samples.y, (samples.x + samples.w) / 2.0, samples.z); -#else - vec3 color = vec3(samples.x, (samples.y + samples.z) / 2.0, samples.w); -#endif + #if defined(CFA_BGGR) + vec3 color = vec3(samples.w, (samples.y + samples.z) / 2.0, samples.x); + #elif defined(CFA_GBRG) + vec3 color = vec3(samples.z, (samples.x + samples.w) / 2.0, samples.y); + #elif defined(CFA_GRBG) + vec3 color = vec3(samples.y, (samples.x + samples.w) / 2.0, samples.z); + #else + vec3 color = vec3(samples.x, (samples.y + samples.z) / 2.0, samples.w); + #endif - color -= blacklevel; - color *= color_matrix; + color -= blacklevel; + color *= color_matrix; - vec3 gamma_color = pow(color, vec3(inv_gamma)); - gl_FragColor = vec4(gamma_color, 1); + vec3 gamma_color = pow(color, vec3(inv_gamma)); + gl_FragColor = vec4(gamma_color, 1); } diff --git a/data/debayer.vert b/data/debayer.vert index 9126c9d..5d1d62b 100644 --- a/data/debayer.vert +++ b/data/debayer.vert @@ -16,10 +16,10 @@ varying vec2 bottom_right_uv; void main() { - top_left_uv = tex_coord - pixel_size / 2.0; - bottom_right_uv = tex_coord + pixel_size / 2.0; - top_right_uv = vec2(top_left_uv.x, bottom_right_uv.y); - bottom_left_uv = vec2(bottom_right_uv.x, top_left_uv.y); + top_left_uv = tex_coord - pixel_size / 2.0; + bottom_right_uv = tex_coord + pixel_size / 2.0; + top_right_uv = vec2(top_left_uv.x, bottom_right_uv.y); + bottom_left_uv = vec2(bottom_right_uv.x, top_left_uv.y); - gl_Position = vec4(transform * vec3(vert, 1), 1); + gl_Position = vec4(transform * vec3(vert, 1), 1); } diff --git a/data/org.postmarketos.Megapixels.gresource.xml b/data/org.postmarketos.Megapixels.gresource.xml index f4a3c8f..5e600ea 100644 --- a/data/org.postmarketos.Megapixels.gresource.xml +++ b/data/org.postmarketos.Megapixels.gresource.xml @@ -17,5 +17,7 @@ solid.frag debayer.vert debayer.frag + yuv.vert + yuv.frag diff --git a/data/yuv.frag b/data/yuv.frag new file mode 100644 index 0000000..d6fceb0 --- /dev/null +++ b/data/yuv.frag @@ -0,0 +1,32 @@ +#ifdef GL_ES +precision highp float; +#endif + +uniform sampler2D texture; +uniform mat3 color_matrix; +uniform float inv_gamma; +uniform float blacklevel; + +varying vec2 top_left_uv; +varying vec2 top_right_uv; +varying vec2 bottom_left_uv; +varying vec2 bottom_right_uv; + +void +main() +{ + // Note the coordinates for texture samples need to be a varying, as the + // Mali-400 has this as a fast path allowing 32-bit floats. Otherwise + // they end up as 16-bit floats and that's not accurate enough. + + vec4 samples = vec4(texture2D(texture, top_left_uv).r, + texture2D(texture, top_right_uv).r, + texture2D(texture, bottom_left_uv).r, + texture2D(texture, bottom_right_uv).r); + vec3 color = vec3(samples.x, samples.y, samples.z); + + color *= color_matrix; + vec3 gamma_color = pow(color, vec3(inv_gamma)); + + gl_FragColor = vec4(gamma_color, 1); +} diff --git a/data/yuv.vert b/data/yuv.vert new file mode 100644 index 0000000..5d1d62b --- /dev/null +++ b/data/yuv.vert @@ -0,0 +1,25 @@ +#ifdef GL_ES +precision mediump float; +#endif + +attribute vec2 vert; +attribute vec2 tex_coord; + +uniform mat3 transform; +uniform vec2 pixel_size; + +varying vec2 top_left_uv; +varying vec2 top_right_uv; +varying vec2 bottom_left_uv; +varying vec2 bottom_right_uv; + +void +main() +{ + top_left_uv = tex_coord - pixel_size / 2.0; + bottom_right_uv = tex_coord + pixel_size / 2.0; + top_right_uv = vec2(top_left_uv.x, bottom_right_uv.y); + bottom_left_uv = vec2(bottom_right_uv.x, top_left_uv.y); + + gl_Position = vec4(transform * vec3(vert, 1), 1); +} diff --git a/src/camera.c b/src/camera.c index 4617635..70be672 100644 --- a/src/camera.c +++ b/src/camera.c @@ -386,6 +386,7 @@ mp_camera_capture_buffer(MPCamera *camera, MPBuffer *buffer) } int format = camera->camera->current_mode->format; + assert(format != 0); uint32_t width = camera->camera->current_mode->width; uint32_t height = camera->camera->current_mode->height; diff --git a/src/gles2_debayer.c b/src/gles2_debayer.c index 1ef16a6..f0bb401 100644 --- a/src/gles2_debayer.c +++ b/src/gles2_debayer.c @@ -12,11 +12,21 @@ GLES2Debayer * gles2_debayer_new(int format) { + // Cannot run on format 0 (Undefined) + assert(format != 0); + uint32_t pixfmt = libmegapixels_format_to_v4l_pixfmt(format); - if (pixfmt != V4L2_PIX_FMT_SBGGR8 && pixfmt != V4L2_PIX_FMT_SGBRG8 && - pixfmt != V4L2_PIX_FMT_SGRBG8 && pixfmt != V4L2_PIX_FMT_SRGGB8 && - pixfmt != V4L2_PIX_FMT_SBGGR10P && pixfmt != V4L2_PIX_FMT_SGBRG10P && - pixfmt != V4L2_PIX_FMT_SGRBG10P && pixfmt != V4L2_PIX_FMT_SRGGB10P) { + + int shader = 0; + + if (pixfmt == V4L2_PIX_FMT_SBGGR8 || pixfmt == V4L2_PIX_FMT_SGBRG8 || + pixfmt == V4L2_PIX_FMT_SGRBG8 || pixfmt == V4L2_PIX_FMT_SRGGB8 || + pixfmt == V4L2_PIX_FMT_SBGGR10P || pixfmt == V4L2_PIX_FMT_SGBRG10P || + pixfmt == V4L2_PIX_FMT_SGRBG10P || pixfmt == V4L2_PIX_FMT_SRGGB10P) { + shader = SHADER_DEBAYER; + } else if (pixfmt == V4L2_PIX_FMT_YUYV) { + shader = SHADER_YUV; + } else { return NULL; } @@ -33,17 +43,22 @@ gles2_debayer_new(int format) const GLchar *def[1] = { format_def }; - GLuint shaders[] = { - gl_util_load_shader("/org/postmarketos/Megapixels/debayer.vert", - GL_VERTEX_SHADER, - NULL, - 0), - gl_util_load_shader("/org/postmarketos/Megapixels/debayer.frag", - GL_FRAGMENT_SHADER, - def, - 1), - }; + char shader_vertex[64]; + char shader_fragment[64]; + snprintf(shader_vertex, + 64, + "/org/postmarketos/Megapixels/%s.vert", + shader == SHADER_DEBAYER ? "debayer" : "yuv"); + snprintf(shader_fragment, + 64, + "/org/postmarketos/Megapixels/%s.frag", + shader == SHADER_DEBAYER ? "debayer" : "yuv"); + GLuint shaders[] = { + gl_util_load_shader(shader_vertex, GL_VERTEX_SHADER, NULL, 0), + gl_util_load_shader(shader_fragment, GL_FRAGMENT_SHADER, def, 1), + }; + printf("Using shader %s and %s\n", shader_vertex, shader_fragment); GLuint program = gl_util_link_program(shaders, 2); glBindAttribLocation(program, VERTEX_ATTRIBUTE, "vert"); glBindAttribLocation(program, TEX_COORD_ATTRIBUTE, "tex_coord"); @@ -51,6 +66,7 @@ gles2_debayer_new(int format) GLES2Debayer *self = malloc(sizeof(GLES2Debayer)); self->format = format; + self->shader = shader; self->frame_buffer = frame_buffer; self->program = program; @@ -116,7 +132,9 @@ gles2_debayer_set_shading(GLES2Debayer *self, multiply_matrices(xyzd65, XYZD65_to_sRGB, colormat); glUniformMatrix3fv( self->uniform_color_matrix, 1, GL_FALSE, colormat); - + } else if (self->shader == SHADER_YUV) { + glUniformMatrix3fv( + self->uniform_color_matrix, 1, GL_FALSE, YUV_to_RGB); } else { glUniformMatrix3fv( self->uniform_color_matrix, 1, GL_FALSE, IDENTITY); diff --git a/src/gles2_debayer.h b/src/gles2_debayer.h index 80aacd3..d5ec6a6 100644 --- a/src/gles2_debayer.h +++ b/src/gles2_debayer.h @@ -4,8 +4,12 @@ #include #include +#define SHADER_DEBAYER 1 +#define SHADER_YUV 2 + typedef struct { int format; + int shader; float forward_matrix[9]; GLuint frame_buffer; diff --git a/src/io_pipeline.c b/src/io_pipeline.c index 5002c67..4c05382 100644 --- a/src/io_pipeline.c +++ b/src/io_pipeline.c @@ -457,6 +457,9 @@ update_state(MPPipeline *pipeline, const mp_state_io *new_state) float score = 0; int area_preview = state_io.preview_width * state_io.preview_height; + if (area_preview == 0) { + area_preview = 1280 * 720; + } for (int m = 0; m < state_io.camera->num_modes; m++) { float mscore = 0; if (state_io.camera->modes[m]->rate > 29) { diff --git a/src/matrix.h b/src/matrix.h index 55f2fd9..29c5d92 100644 --- a/src/matrix.h +++ b/src/matrix.h @@ -24,6 +24,14 @@ static float XYZD65_to_sRGB[] = { // clang-format on }; +static float YUV_to_RGB[] = { + // clang-format off + 0.299f, 0.587f, 0.114f, + -0.299f, -0.587f, 0.886f, + 0.701f, -0.597f, -0.114f + // clang-format on +}; + void print_matrix(float m[9]); void multiply_matrices(const float a[9], const float b[9], float out[9]);