mutter/src/compositor/meta-multi-texture-format.c
Sebastian Wick dbdc821ca7 multi-texture-format: Expose immutable fields directly
Split the struct into mutable and immutable parts. Access the mutable
parts via getters and the immutable parts via a single struct. This
avoids copying around the immutable parts.

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3280>
2023-11-22 12:11:38 +00:00

231 lines
8.0 KiB
C

/*
* 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/>.
*/
/**
* SECTION:meta-multi-texture-format
* @title: MetaMultiTextureFormat
* @short_description: A representation for complex pixel formats
*
* Some pixel formats that are used in the wild are a bit more complex than
* just ARGB and all its variants. For example: a component might be put in a
* different plane (i.e. at a different place in memory). Another example are
* formats that use Y, U, and V components rather than RGB; if we composite them
* onto an RGBA framebuffer, we have to make sure for example that these get
* converted to the right color format first (using e.g. a shader).
*/
#include "config.h"
#include "compositor/meta-multi-texture-format-private.h"
#include <cogl/cogl.h>
#include <stdlib.h>
#include <string.h>
static const char *shader_global_conversions =
"vec4 yuv_to_rgb(vec4 yuva) \n"
"{ \n"
" vec4 res; \n"
" float Y = 1.16438356 * (yuva.x - 0.0625); \n"
" float su = yuva.y - 0.5; \n"
" float sv = yuva.z - 0.5; \n"
" res.r = Y + 1.59602678 * sv; \n"
" res.g = Y - 0.39176229 * su - 0.81296764 * sv; \n"
" res.b = Y + 2.01723214 * su; \n"
" res.rgb *= yuva.w; \n"
" res.a = yuva.w; \n"
" return res; \n"
"} \n";
static const char rgba_shader[] =
"cogl_color_out = \n"
" texture2D(cogl_sampler0, cogl_tex_coord0_in.st) * cogl_color_in.a; \n";
/* Shader for a single YUV plane */
static const char y_xuxv_shader[] =
"vec4 yuva = vec4(0.0, 0.0, 0.0, cogl_color_in.a); \n"
"yuva.x = texture2D(cogl_sampler0, cogl_tex_coord0_in.st).x; \n"
"yuva.yz = texture2D(cogl_sampler1, cogl_tex_coord1_in.st).ga; \n"
"cogl_color_out = yuv_to_rgb(yuva); \n";
/* Shader for 1 Y-plane and 1 UV-plane */
static const char y_uv_shader[] =
"vec4 yuva = vec4(0.0, 0.0, 0.0, cogl_color_in.a); \n"
"yuva.x = texture2D(cogl_sampler0, cogl_tex_coord0_in.st).x; \n"
"yuva.yz = texture2D(cogl_sampler1, cogl_tex_coord1_in.st).rg; \n"
"cogl_color_out = yuv_to_rgb(yuva); \n";
/* Shader for 1 Y-plane, 1 U-plane and 1 V-plane */
static const char y_u_v_shader[] =
"vec4 yuva = vec4(0.0, 0.0, 0.0, cogl_color_in.a); \n"
"yuva.x = texture2D(cogl_sampler0, cogl_tex_coord0_in.st).x; \n"
"yuva.y = texture2D(cogl_sampler1, cogl_tex_coord1_in.st).x; \n"
"yuva.z = texture2D(cogl_sampler2, cogl_tex_coord2_in.st).x; \n"
"cogl_color_out = yuv_to_rgb(yuva); \n";
typedef struct _MetaMultiTextureFormatFullInfo
{
MetaMultiTextureFormatInfo info;
/* Name */
const char *name;
/* Shader to convert to RGBA (or NULL) */
const char *rgb_shader;
/* Cached snippet */
GOnce snippet_once;
} MetaMultiTextureFormatFullInfo;
/* NOTE: The actual enum values are used as the index, so you don't need to
* loop over the table */
static MetaMultiTextureFormatFullInfo multi_format_table[] = {
/* Invalid */
[META_MULTI_TEXTURE_FORMAT_INVALID] = {},
/* Simple */
[META_MULTI_TEXTURE_FORMAT_SIMPLE] = {
.name = "",
.rgb_shader = rgba_shader,
.snippet_once = G_ONCE_INIT,
.info = {
.n_planes = 1,
.subformats = { COGL_PIXEL_FORMAT_ANY },
.plane_indices = { 0 },
.hsub = { 1 },
.vsub = { 1 },
},
},
/* Packed YUV */
[META_MULTI_TEXTURE_FORMAT_YUYV] = {
.name = "YUYV",
.rgb_shader = y_xuxv_shader,
.snippet_once = G_ONCE_INIT,
.info = {
.n_planes = 2,
.subformats = { COGL_PIXEL_FORMAT_RG_88, COGL_PIXEL_FORMAT_BGRA_8888_PRE },
.plane_indices = { 0, 0 },
.hsub = { 1, 2 },
.vsub = { 1, 1 },
},
},
/* 2 plane YUV */
[META_MULTI_TEXTURE_FORMAT_NV12] = {
.name = "NV12",
.rgb_shader = y_uv_shader,
.snippet_once = G_ONCE_INIT,
.info = {
.n_planes = 2,
.subformats = { COGL_PIXEL_FORMAT_R_8, COGL_PIXEL_FORMAT_RG_88 },
.plane_indices = { 0, 1 },
.hsub = { 1, 2 },
.vsub = { 1, 2 },
},
},
[META_MULTI_TEXTURE_FORMAT_P010] = {
.name = "P010",
.rgb_shader = y_uv_shader,
.snippet_once = G_ONCE_INIT,
.info = {
.n_planes = 2,
.subformats = { COGL_PIXEL_FORMAT_R_16, COGL_PIXEL_FORMAT_RG_1616 },
.plane_indices = { 0, 1 },
.hsub = { 1, 2 },
.vsub = { 1, 2 },
},
},
/* 3 plane YUV */
[META_MULTI_TEXTURE_FORMAT_YUV420] = {
.name = "YUV420",
.rgb_shader = y_u_v_shader,
.snippet_once = G_ONCE_INIT,
.info = {
.n_planes = 3,
.subformats = { COGL_PIXEL_FORMAT_R_8, COGL_PIXEL_FORMAT_R_8, COGL_PIXEL_FORMAT_R_8 },
.plane_indices = { 0, 1, 2 },
.hsub = { 1, 2, 2 },
.vsub = { 1, 2, 2 },
},
},
};
const char *
meta_multi_texture_format_to_string (MetaMultiTextureFormat format)
{
g_return_val_if_fail (format < G_N_ELEMENTS (multi_format_table), NULL);
return multi_format_table[format].name;
}
const MetaMultiTextureFormatInfo *
meta_multi_texture_format_get_info (MetaMultiTextureFormat format)
{
g_return_val_if_fail (format < G_N_ELEMENTS (multi_format_table), NULL);
return &multi_format_table[format].info;
}
static gpointer
create_globals_snippet (gpointer data)
{
return cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT_GLOBALS,
shader_global_conversions,
NULL);
}
static gpointer
create_format_snippet (gpointer data)
{
MetaMultiTextureFormat format =
(MetaMultiTextureFormat) GPOINTER_TO_INT (data);
return cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT,
NULL,
multi_format_table[format].rgb_shader);
}
gboolean
meta_multi_texture_format_get_snippets (MetaMultiTextureFormat format,
CoglSnippet **fragment_globals_snippet,
CoglSnippet **fragment_snippet)
{
g_return_val_if_fail (format < G_N_ELEMENTS (multi_format_table), FALSE);
if (multi_format_table[format].rgb_shader == NULL)
return FALSE;
if (fragment_globals_snippet)
{
static GOnce globals_once = G_ONCE_INIT;
CoglSnippet *globals_snippet;
globals_snippet = g_once (&globals_once, create_globals_snippet, NULL);
*fragment_globals_snippet = g_object_ref (globals_snippet);
}
if (fragment_snippet)
{
CoglSnippet *format_snippet;
format_snippet = g_once (&multi_format_table[format].snippet_once,
create_format_snippet,
GINT_TO_POINTER (format));
*fragment_snippet = g_object_ref (format_snippet);
}
return TRUE;
}