summaryrefslogtreecommitdiff
path: root/cogl/cogl/cogl-pixel-format-conversion.c
diff options
context:
space:
mode:
Diffstat (limited to 'cogl/cogl/cogl-pixel-format-conversion.c')
-rw-r--r--cogl/cogl/cogl-pixel-format-conversion.c163
1 files changed, 163 insertions, 0 deletions
diff --git a/cogl/cogl/cogl-pixel-format-conversion.c b/cogl/cogl/cogl-pixel-format-conversion.c
new file mode 100644
index 000000000..6b505705e
--- /dev/null
+++ b/cogl/cogl/cogl-pixel-format-conversion.c
@@ -0,0 +1,163 @@
+/*
+ * Authored By Niels De Graef <niels.degraef@barco.com>
+ *
+ * Copyright (C) 2018 Barco NV
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cogl-config.h"
+
+#include "cogl-object-private.h"
+#include "cogl-gtype-private.h"
+#include "cogl-pixel-format-conversion.h"
+#include "cogl-snippet.h"
+#include "cogl-pipeline-layer-state.h"
+#include "cogl-pipeline-state.h"
+
+#define _COGL_YUV_TO_RGBA(res, y, u, v) \
+ res ".r = " y " + 1.59765625 * " v ";\n" \
+ res ".g = " y " - 0.390625 * " u " - 0.8125 * " v ";\n" \
+ res ".b = " y " + 2.015625 * " u ";\n" \
+ res ".a = 1.0;\n"
+
+static const gchar nv12_to_rgba_shader[] =
+ "vec4\n"
+ "cogl_nv12_to_rgba (vec2 UV)\n"
+ "{\n"
+ " vec4 color;\n"
+ " float y = 1.1640625 * (texture2D (cogl_sampler0, UV).x - 0.0625);\n"
+ " vec2 uv = texture2D (cogl_sampler1, UV).rg;\n"
+ " uv -= 0.5;\n"
+ " float u = uv.x;\n"
+ " float v = uv.y;\n"
+ _COGL_YUV_TO_RGBA ("color", "y", "u", "v")
+ " return color;\n"
+ "}\n";
+
+static const gchar yuv_to_rgba_shader[] =
+ "vec4\n"
+ "cogl_yuv_to_rgba (vec2 UV)\n"
+ "{\n"
+ " vec4 color;\n"
+ " float y = 1.16438356 * (texture2D(cogl_sampler0, UV).x - 0.0625);\n"
+ " float u = texture2D(cogl_sampler1, UV).x - 0.5;\n"
+ " float v = texture2D(cogl_sampler2, UV).x - 0.5;\n"
+ _COGL_YUV_TO_RGBA ("color", "y", "u", "v")
+ " return color;\n"
+ "}\n";
+
+struct _CoglPixelFormatConversion
+{
+ CoglObject _parent;
+
+ CoglSnippet *vertex_declaration_snippet;
+ CoglSnippet *fragment_declaration_snippet;
+
+ CoglSnippet *fragment_execution_snippet;
+};
+
+static void
+_cogl_pixel_format_conversion_free (CoglPixelFormatConversion *self);
+
+COGL_OBJECT_DEFINE (PixelFormatConversion, pixel_format_conversion);
+COGL_GTYPE_DEFINE_CLASS (PixelFormatConversion, pixel_format_conversion);
+
+
+void
+cogl_pixel_format_conversion_attach_to_pipeline (CoglPixelFormatConversion *self,
+ CoglPipeline *pipeline,
+ gint layer)
+{
+ cogl_pipeline_add_snippet (pipeline, self->fragment_declaration_snippet);
+ cogl_pipeline_add_snippet (pipeline, self->vertex_declaration_snippet);
+
+ cogl_pipeline_add_layer_snippet (pipeline,
+ layer,
+ self->fragment_execution_snippet);
+}
+
+static gboolean
+get_cogl_snippets (CoglPixelFormat format,
+ CoglSnippet **vertex_snippet_out,
+ CoglSnippet **fragment_snippet_out,
+ CoglSnippet **layer_snippet_out)
+{
+ const gchar *global_hook;
+ const gchar *layer_hook;
+
+ switch (format)
+ {
+ case COGL_PIXEL_FORMAT_YUV444:
+ global_hook = yuv_to_rgba_shader;
+ layer_hook = "cogl_layer = cogl_yuv_to_rgba(cogl_tex_coord0_in.st);\n";
+ break;
+ case COGL_PIXEL_FORMAT_NV12:
+ /* XXX are we using Y_UV or Y_xUxV? Maybe check for RG support? */
+ global_hook = nv12_to_rgba_shader;
+ layer_hook = "cogl_layer = cogl_nv12_to_rgba(cogl_tex_coord0_in.st);\n";
+ break;
+ default:
+ *vertex_snippet_out = NULL;
+ *fragment_snippet_out = NULL;
+ *layer_snippet_out = NULL;
+ return FALSE;
+ }
+
+ *vertex_snippet_out = cogl_snippet_new (COGL_SNIPPET_HOOK_VERTEX_GLOBALS,
+ global_hook,
+ NULL);
+
+ *fragment_snippet_out = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT_GLOBALS,
+ global_hook,
+ NULL);
+
+ *layer_snippet_out = cogl_snippet_new (COGL_SNIPPET_HOOK_LAYER_FRAGMENT,
+ NULL,
+ layer_hook);
+
+ return TRUE;
+}
+
+static void
+_cogl_pixel_format_conversion_free (CoglPixelFormatConversion *self)
+{
+ cogl_clear_object (&self->vertex_declaration_snippet);
+ cogl_clear_object (&self->fragment_declaration_snippet);
+ cogl_clear_object (&self->fragment_execution_snippet);
+}
+
+CoglPixelFormatConversion *
+cogl_pixel_format_conversion_new (CoglPixelFormat format)
+{
+ CoglPixelFormatConversion *self;
+ CoglSnippet *vertex_declaration_snippet;
+ CoglSnippet *fragment_declaration_snippet;
+ CoglSnippet *fragment_execution_snippet;
+
+ if (!get_cogl_snippets (format,
+ &vertex_declaration_snippet,
+ &fragment_declaration_snippet,
+ &fragment_execution_snippet))
+ return NULL;
+
+ self = g_slice_new0 (CoglPixelFormatConversion);
+ _cogl_pixel_format_conversion_object_new (self);
+
+ self->vertex_declaration_snippet = vertex_declaration_snippet;
+ self->fragment_declaration_snippet = fragment_declaration_snippet;
+ self->fragment_execution_snippet = fragment_execution_snippet;
+
+ return self;
+}