gsk: Support dmabuf textures

Support dmabuf textures in the GL renderer.

This copies the approach taken by mutter for
yuv dmabuf conversion.
This commit is contained in:
Matthias Clasen
2023-10-03 17:28:17 -04:00
parent 4957bed573
commit e83dcc4cab
8 changed files with 572 additions and 47 deletions

View File

@@ -42,9 +42,16 @@
#include <gdk/gdkmemorytextureprivate.h>
#include <gdk/gdkprofilerprivate.h>
#include <gdk/gdktextureprivate.h>
#include <gdk/gdkdmabuftextureprivate.h>
#include <gdk/gdkmemoryformatprivate.h>
#ifdef HAVE_EGL
#include <epoxy/egl.h>
#endif
#ifdef HAVE_LINUX_DMA_BUF_H
#include <drm/drm_fourcc.h>
#endif
G_DEFINE_TYPE (GskGLDriver, gsk_gl_driver, G_TYPE_OBJECT)
static guint
@@ -224,6 +231,8 @@ gsk_gl_driver_dispose (GObject *object)
GSK_GL_DELETE_PROGRAM(name); \
GSK_GL_DELETE_PROGRAM(name ## _no_clip); \
GSK_GL_DELETE_PROGRAM(name ## _rect_clip);
#define GSK_GL_DEFINE_PROGRAM_NO_CLIP(name, resource, uniforms) \
GSK_GL_DELETE_PROGRAM(name);
#define GSK_GL_DELETE_PROGRAM(name) \
G_STMT_START { \
if (self->name) \
@@ -238,6 +247,7 @@ gsk_gl_driver_dispose (GObject *object)
#undef GSK_GL_SHADER_JOINED
#undef GSK_GL_ADD_UNIFORM
#undef GSK_GL_DEFINE_PROGRAM
#undef GSK_GL_DEFINE_PROGRAM_NO_CLIP
if (self->shader_cache != NULL)
{
@@ -373,6 +383,11 @@ gsk_gl_driver_load_programs (GskGLDriver *self,
GSK_GL_COMPILE_PROGRAM(name ## _no_clip, uniforms, "#define NO_CLIP 1\n"); \
GSK_GL_COMPILE_PROGRAM(name ## _rect_clip, uniforms, "#define RECT_CLIP 1\n"); \
GSK_GL_COMPILE_PROGRAM(name, uniforms, "");
#define GSK_GL_DEFINE_PROGRAM_NO_CLIP(name, sources, uniforms) \
gsk_gl_compiler_set_source (compiler, GSK_GL_COMPILER_VERTEX, NULL); \
gsk_gl_compiler_set_source (compiler, GSK_GL_COMPILER_FRAGMENT, NULL); \
sources \
GSK_GL_COMPILE_PROGRAM(name, uniforms, "#define NO_CLIP 1\n");
#define GSK_GL_COMPILE_PROGRAM(name, uniforms, clip) \
G_STMT_START { \
GskGLProgram *program; \
@@ -399,8 +414,8 @@ gsk_gl_driver_load_programs (GskGLDriver *self,
g_steal_pointer (&program); \
} G_STMT_END;
# include "gskglprograms.defs"
#undef GSK_GL_DEFINE_PROGRAM_CLIP
#undef GSK_GL_DEFINE_PROGRAM
#undef GSK_GL_DEFINE_PROGRAM_NO_CLIP
#undef GSK_GL_ADD_UNIFORM
#undef GSK_GL_SHADER_SINGLE
#undef GSK_GL_SHADER_JOINED
@@ -703,6 +718,321 @@ gsk_gl_driver_cache_texture (GskGLDriver *self,
}
}
#if defined(HAVE_EGL) && defined(HAVE_LINUX_DMA_BUF_H)
static int
import_dmabuf_planes (EGLDisplay egl_display,
int width,
int height,
unsigned int fourcc,
guint64 modifier,
unsigned int n_planes,
int *fds,
unsigned int *strides,
unsigned int *offsets)
{
EGLint attribs[64];
EGLImage image;
guint texture_id;
int i;
g_assert (1 <= n_planes && n_planes <= 4);
GSK_DEBUG (OPENGL,
"Importing dma-buf into GL via EGLImage. Format %c%c%c%c:%#lx",
fourcc & 0xff, (fourcc >> 8) & 0xff, (fourcc >> 16) & 0xff, (fourcc >> 24) & 0xff, modifier);
i = 0;
attribs[i++] = EGL_WIDTH;
attribs[i++] = width;
attribs[i++] = EGL_HEIGHT;
attribs[i++] = height;
attribs[i++] = EGL_LINUX_DRM_FOURCC_EXT;
attribs[i++] = fourcc;
#define ADD_PLANE(plane) \
{ \
if (modifier != DRM_FORMAT_MOD_INVALID) \
{ \
attribs[i++] = EGL_DMA_BUF_PLANE## plane ##_MODIFIER_LO_EXT; \
attribs[i++] = modifier & 0xFFFFFFFF; \
attribs[i++] = EGL_DMA_BUF_PLANE## plane ## _MODIFIER_HI_EXT; \
attribs[i++] = modifier >> 32; \
} \
attribs[i++] = EGL_DMA_BUF_PLANE## plane ##_FD_EXT; \
attribs[i++] = fds[plane]; \
attribs[i++] = EGL_DMA_BUF_PLANE## plane ##_PITCH_EXT; \
attribs[i++] = strides[plane]; \
attribs[i++] = EGL_DMA_BUF_PLANE## plane ##_OFFSET_EXT; \
attribs[i++] = offsets[plane]; \
}
ADD_PLANE (0);
if (n_planes > 1) ADD_PLANE (1);
if (n_planes > 2) ADD_PLANE (2);
if (n_planes > 3) ADD_PLANE (3);
attribs[i++] = EGL_NONE;
image = eglCreateImageKHR (egl_display,
EGL_NO_CONTEXT,
EGL_LINUX_DMA_BUF_EXT,
(EGLClientBuffer)NULL,
attribs);
if (image == EGL_NO_IMAGE)
{
g_warning ("Failed to create EGL image: %#x\n", eglGetError ());
return 0;
}
glGenTextures (1, &texture_id);
glBindTexture (GL_TEXTURE_2D, texture_id);
glEGLImageTargetTexture2DOES (GL_TEXTURE_2D, image);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
eglDestroyImageKHR (egl_display, image);
return texture_id;
}
static void
set_viewport_for_size (GskGLDriver *self,
GskGLProgram *program,
float width,
float height)
{
float viewport[4] = { 0, 0, width, height };
gsk_gl_uniform_state_set4fv (program->uniforms,
program->program_info,
UNIFORM_SHARED_VIEWPORT, 0,
1,
(const float *)&viewport);
self->stamps[UNIFORM_SHARED_VIEWPORT]++;
}
#define ORTHO_NEAR_PLANE -10000
#define ORTHO_FAR_PLANE 10000
static void
set_projection_for_size (GskGLDriver *self,
GskGLProgram *program,
float width,
float height)
{
graphene_matrix_t projection;
graphene_matrix_init_ortho (&projection, 0, width, 0, height, ORTHO_NEAR_PLANE, ORTHO_FAR_PLANE);
graphene_matrix_scale (&projection, 1, -1, 1);
gsk_gl_uniform_state_set_matrix (program->uniforms,
program->program_info,
UNIFORM_SHARED_PROJECTION, 0,
&projection);
self->stamps[UNIFORM_SHARED_PROJECTION]++;
}
static void
reset_modelview (GskGLDriver *self,
GskGLProgram *program)
{
graphene_matrix_t modelview;
graphene_matrix_init_identity (&modelview);
gsk_gl_uniform_state_set_matrix (program->uniforms,
program->program_info,
UNIFORM_SHARED_MODELVIEW, 0,
&modelview);
self->stamps[UNIFORM_SHARED_MODELVIEW]++;
}
static void
draw_rect (GskGLCommandQueue *command_queue,
float min_x,
float min_y,
float max_x,
float max_y)
{
GskGLDrawVertex *vertices = gsk_gl_command_queue_add_vertices (command_queue);
float min_u = 0;
float max_u = 1;
float min_v = 1;
float max_v = 0;
guint16 c = FP16_ZERO;
vertices[0] = (GskGLDrawVertex) { .position = { min_x, min_y }, .uv = { min_u, min_v }, .color = { c, c, c, c } };
vertices[1] = (GskGLDrawVertex) { .position = { min_x, max_y }, .uv = { min_u, max_v }, .color = { c, c, c, c } };
vertices[2] = (GskGLDrawVertex) { .position = { max_x, min_y }, .uv = { max_u, min_v }, .color = { c, c, c, c } };
vertices[3] = (GskGLDrawVertex) { .position = { max_x, max_y }, .uv = { max_u, max_v }, .color = { c, c, c, c } };
vertices[4] = (GskGLDrawVertex) { .position = { min_x, max_y }, .uv = { min_u, max_v }, .color = { c, c, c, c } };
vertices[5] = (GskGLDrawVertex) { .position = { max_x, min_y }, .uv = { max_u, min_v }, .color = { c, c, c, c } };
}
typedef struct _TextureFormatInfo TextureFormatInfo;
struct _TextureFormatInfo
{
int n_planes;
unsigned int subformats[3];
int plane_indices[3];
int hsub[3];
int vsub[3];
int uniforms[3];
};
static TextureFormatInfo texture_format_info[] = {
{ .n_planes = 2,
.subformats = { DRM_FORMAT_GR88, DRM_FORMAT_ARGB8888 },
.plane_indices = { 0, 0 },
.hsub = { 1, 2 },
.vsub = { 1, 1 },
.uniforms = { UNIFORM_SHARED_SOURCE, UNIFORM_YUYV_SOURCE2 },
},
{ .n_planes = 2,
.subformats = { DRM_FORMAT_R8, DRM_FORMAT_GR88 },
.plane_indices = { 0, 1 },
.hsub = { 1, 2 },
.vsub = { 1, 2 },
.uniforms = { UNIFORM_SHARED_SOURCE, UNIFORM_NV12_SOURCE2 },
},
{ .n_planes = 2,
.subformats = { DRM_FORMAT_R16, DRM_FORMAT_GR1616 },
.plane_indices = { 0, 1 },
.hsub = { 1, 2 },
.vsub = { 1, 2 },
.uniforms = { UNIFORM_SHARED_SOURCE, UNIFORM_NV12_SOURCE2 },
},
{ .n_planes = 3,
.subformats = { DRM_FORMAT_R8, DRM_FORMAT_R8, DRM_FORMAT_R8 },
.plane_indices = { 0, 1, 2 },
.hsub = { 1, 2, 2 },
.vsub = { 1, 2, 2 },
.uniforms = { UNIFORM_SHARED_SOURCE, UNIFORM_YUV420_SOURCE2, UNIFORM_YUV420_SOURCE3 },
},
};
static unsigned int release_render_target (GskGLDriver *self,
GskGLRenderTarget *render_target,
gboolean release_texture,
gboolean cache_texture);
static unsigned int
gsk_gl_driver_import_dmabuf_texture (GskGLDriver *self,
GdkDmabufTexture *texture)
{
GdkGLContext *context = self->command_queue->context;
GdkDisplay *display = gdk_gl_context_get_display (context);
EGLDisplay egl_display;
int width, height;
guint64 modifier;
TextureFormatInfo *info;
GskGLProgram *program;
GskGLRenderTarget *render_target;
guint prev_fbo;
egl_display = gdk_display_get_egl_display (display);
if (egl_display == NULL)
{
g_warning ("Can't import dmabufs when not using EGL");
return 0;
}
if (!display->have_egl_dma_buf_import)
{
g_warning ("EGL does ont support importing dmabufs");
return 0;
}
gdk_gl_context_make_current (context);
width = gdk_texture_get_width (GDK_TEXTURE (texture));
height = gdk_texture_get_height (GDK_TEXTURE (texture));
modifier = gdk_dmabuf_texture_get_modifier (texture);
if (gdk_dmabuf_texture_get_fourcc (texture) == DRM_FORMAT_YUYV)
{
info = &texture_format_info[0];
program = self->yuyv;
}
else if (gdk_dmabuf_texture_get_fourcc (texture) == DRM_FORMAT_NV12)
{
info = &texture_format_info[1];
program = self->nv12;
}
else if (gdk_dmabuf_texture_get_fourcc (texture) == DRM_FORMAT_P010)
{
info = &texture_format_info[2];
program = self->nv12;
}
else if (gdk_dmabuf_texture_get_fourcc (texture) == DRM_FORMAT_YUV420)
{
info = &texture_format_info[3];
program = self->yuv420;
}
else
{
return import_dmabuf_planes (egl_display,
gdk_texture_get_width (GDK_TEXTURE (texture)),
gdk_texture_get_height (GDK_TEXTURE (texture)),
gdk_dmabuf_texture_get_fourcc (texture),
gdk_dmabuf_texture_get_modifier (texture),
gdk_dmabuf_texture_get_n_planes (texture),
gdk_dmabuf_texture_get_fds (texture),
gdk_dmabuf_texture_get_strides (texture),
gdk_dmabuf_texture_get_offsets (texture));
}
gsk_gl_driver_create_render_target (self, width, height, GL_RGBA8, &render_target);
prev_fbo = gsk_gl_command_queue_bind_framebuffer (self->command_queue, render_target->framebuffer_id);
gsk_gl_command_queue_clear (self->command_queue, 0, &GRAPHENE_RECT_INIT (0, 0, width, height));
gsk_gl_command_queue_begin_draw (self->command_queue, program->program_info, width, height);
set_projection_for_size (self, program, width, height);
set_viewport_for_size (self, program, width, height);
reset_modelview (self, program);
for (int i = 0; i < info->n_planes; i++)
{
int plane = info->plane_indices[i];
int texture_id = import_dmabuf_planes (egl_display,
width / info->hsub[i],
height / info->vsub[i],
info->subformats[i],
modifier,
1,
gdk_dmabuf_texture_get_fds (texture) + plane,
gdk_dmabuf_texture_get_strides (texture) + plane,
gdk_dmabuf_texture_get_offsets (texture) + plane);
gsk_gl_program_set_uniform_texture (program,
info->uniforms[i], 0,
GL_TEXTURE_2D, GL_TEXTURE0 + i, texture_id);
gsk_gl_driver_autorelease_texture (self, texture_id);
}
draw_rect (self->command_queue, 0, 0, width, height);
gsk_gl_command_queue_end_draw (self->command_queue);
gsk_gl_command_queue_bind_framebuffer (self->command_queue, prev_fbo);
return release_render_target (self, render_target, FALSE, FALSE);
}
#else
static unsigned int
gsk_gl_driver_import_dmabuf_texture (GskGLDriver *self,
GdkDmabufTexture *texture)
{
return 0;
}
#endif /* HAVE_EGL && HAVE_LINUX_DMA_BUF_H */
/**
* gsk_gl_driver_load_texture:
* @self: a `GdkTexture`
@@ -759,7 +1089,11 @@ gsk_gl_driver_load_texture (GskGLDriver *self,
return t->texture_id;
}
if (GDK_IS_GL_TEXTURE (texture))
if (GDK_IS_DMABUF_TEXTURE (texture))
{
texture_id = gsk_gl_driver_import_dmabuf_texture (self, GDK_DMABUF_TEXTURE (texture));
}
else if (GDK_IS_GL_TEXTURE (texture))
{
GdkGLTexture *gl_texture = (GdkGLTexture *) texture;
GdkGLContext *texture_context = gdk_gl_texture_get_context (gl_texture);
@@ -788,9 +1122,8 @@ gsk_gl_driver_load_texture (GskGLDriver *self,
width = gdk_texture_get_width (texture);
height = gdk_texture_get_height (texture);
t = gsk_gl_texture_new (texture_id,
width, height,
self->current_frame_id);
t = gsk_gl_texture_new (texture_id, width, height, self->current_frame_id);
if (ensure_mipmap)
{
glBindTexture (GL_TEXTURE_2D, t->texture_id);
@@ -962,6 +1295,47 @@ gsk_gl_driver_create_render_target (GskGLDriver *self,
return FALSE;
}
static unsigned int
release_render_target (GskGLDriver *self,
GskGLRenderTarget *render_target,
gboolean release_texture,
gboolean cache_texture)
{
guint texture_id;
g_return_val_if_fail (GSK_IS_GL_DRIVER (self), 0);
g_return_val_if_fail (render_target != NULL, 0);
if (release_texture)
{
texture_id = 0;
g_ptr_array_add (self->render_targets, render_target);
}
else
{
texture_id = render_target->texture_id;
if (cache_texture)
{
GskGLTexture *texture;
texture = gsk_gl_texture_new (render_target->texture_id,
render_target->width,
render_target->height,
self->current_frame_id);
g_hash_table_insert (self->textures,
GUINT_TO_POINTER (texture_id),
g_steal_pointer (&texture));
}
gsk_gl_driver_autorelease_framebuffer (self, render_target->framebuffer_id);
g_free (render_target);
}
return texture_id;
}
/**
* gsk_gl_driver_release_render_target:
* @self: a `GskGLDriver`
@@ -987,36 +1361,7 @@ gsk_gl_driver_release_render_target (GskGLDriver *self,
GskGLRenderTarget *render_target,
gboolean release_texture)
{
guint texture_id;
g_return_val_if_fail (GSK_IS_GL_DRIVER (self), 0);
g_return_val_if_fail (render_target != NULL, 0);
if (release_texture)
{
texture_id = 0;
g_ptr_array_add (self->render_targets, render_target);
}
else
{
GskGLTexture *texture;
texture_id = render_target->texture_id;
texture = gsk_gl_texture_new (render_target->texture_id,
render_target->width,
render_target->height,
self->current_frame_id);
g_hash_table_insert (self->textures,
GUINT_TO_POINTER (texture_id),
g_steal_pointer (&texture));
gsk_gl_driver_autorelease_framebuffer (self, render_target->framebuffer_id);
g_free (render_target);
}
return texture_id;
return release_render_target (self, render_target, release_texture, TRUE);
}
/**

View File

@@ -69,7 +69,9 @@ typedef struct {
#define CONCAT_EXPANDED2(a,b) a##b
#define GSK_GL_ADD_UNIFORM(pos, KEY, name) UNIFORM_##KEY = UNIFORM_SHARED_LAST + pos,
#define GSK_GL_DEFINE_PROGRAM(name, resource, uniforms) enum { uniforms };
#define GSK_GL_DEFINE_PROGRAM_NO_CLIP(name, resource, uniforms) enum { uniforms };
# include "gskglprograms.defs"
#undef GSK_GL_DEFINE_PROGRAM_NO_CLIP
#undef GSK_GL_DEFINE_PROGRAM
#undef GSK_GL_ADD_UNIFORM
#undef GSK_GL_NO_UNIFORMS
@@ -116,10 +118,13 @@ struct _GskGLDriver
GskGLProgram *name ## _no_clip; \
GskGLProgram *name ## _rect_clip; \
GskGLProgram *name;
#define GSK_GL_DEFINE_PROGRAM_NO_CLIP(name, resource, uniforms) \
GskGLProgram *name;
# include "gskglprograms.defs"
#undef GSK_GL_NO_UNIFORMS
#undef GSK_GL_ADD_UNIFORM
#undef GSK_GL_DEFINE_PROGRAM
#undef GSK_GL_DEFINE_PROGRAM_NO_CLIP
gint64 current_frame_id;

View File

@@ -87,3 +87,22 @@ GSK_GL_DEFINE_PROGRAM (unblurred_outset_shadow,
GSK_GL_ADD_UNIFORM (1, UNBLURRED_OUTSET_SHADOW_SPREAD, u_spread)
GSK_GL_ADD_UNIFORM (2, UNBLURRED_OUTSET_SHADOW_OFFSET, u_offset)
GSK_GL_ADD_UNIFORM (3, UNBLURRED_OUTSET_SHADOW_OUTLINE_RECT, u_outline_rect))
/* Texture conversion shaders.
*
* Note: If you add new formats here, they need to be added
* to the list of supported formats in gdk/gdkdmabuftexture.c.
*/
GSK_GL_DEFINE_PROGRAM_NO_CLIP (yuyv,
GSK_GL_SHADER_SINGLE (GSK_GL_SHADER_RESOURCE ("yuyv.glsl")),
GSK_GL_ADD_UNIFORM (1, YUYV_SOURCE2, u_source2))
GSK_GL_DEFINE_PROGRAM_NO_CLIP (nv12,
GSK_GL_SHADER_SINGLE (GSK_GL_SHADER_RESOURCE ("nv12.glsl")),
GSK_GL_ADD_UNIFORM (1, NV12_SOURCE2, u_source2))
GSK_GL_DEFINE_PROGRAM_NO_CLIP (yuv420,
GSK_GL_SHADER_SINGLE (GSK_GL_SHADER_RESOURCE ("yuv420.glsl")),
GSK_GL_ADD_UNIFORM (1, YUV420_SOURCE2, u_source2)
GSK_GL_ADD_UNIFORM (2, YUV420_SOURCE3, u_source2))

View File

@@ -30,6 +30,8 @@
#include <gsk/gskglshaderprivate.h>
#include <gdk/gdktextureprivate.h>
#include <gdk/gdkmemorytextureprivate.h>
#include <gdk/gdkdmabuftextureprivate.h>
#include <gdk/gdkdisplayprivate.h>
#include <gsk/gsktransformprivate.h>
#include <gsk/gskroundedrectprivate.h>
#include <gsk/gskrectprivate.h>
@@ -43,10 +45,15 @@
#include "gskglprogramprivate.h"
#include "gskglrenderjobprivate.h"
#include "gskglshadowlibraryprivate.h"
#include "gskdebugprivate.h"
#include "ninesliceprivate.h"
#include "fp16private.h"
#include <epoxy/egl.h>
#include <drm/drm_fourcc.h>
#define ORTHO_NEAR_PLANE -10000
#define ORTHO_FAR_PLANE 10000
#define MAX_GRADIENT_STOPS 6
@@ -3630,16 +3637,11 @@ gsk_gl_render_job_upload_texture (GskGLRenderJob *job,
gboolean ensure_mipmap,
GskGLRenderOffscreen *offscreen)
{
GdkGLTexture *gl_texture = NULL;
if (GDK_IS_GL_TEXTURE (texture))
gl_texture = GDK_GL_TEXTURE (texture);
if (!ensure_mipmap &&
gsk_gl_texture_library_can_cache ((GskGLTextureLibrary *)job->driver->icons_library,
texture->width,
texture->height) &&
!gl_texture)
!(GDK_IS_GL_TEXTURE (texture) || GDK_IS_DMABUF_TEXTURE (texture)))
{
const GskGLIconData *icon_data;
@@ -3653,16 +3655,18 @@ gsk_gl_render_job_upload_texture (GskGLRenderJob *job,
/* Only generate a mipmap if it does not make use reupload
* a GL texture which we could otherwise use directly.
*/
if (gl_texture &&
gdk_gl_context_is_shared (gdk_gl_texture_get_context (gl_texture), job->command_queue->context))
ensure_mipmap = gdk_gl_texture_has_mipmap (gl_texture);
if (GDK_IS_GL_TEXTURE (texture) &&
gdk_gl_context_is_shared (gdk_gl_texture_get_context (GDK_GL_TEXTURE (texture)),
job->command_queue->context))
ensure_mipmap = gdk_gl_texture_has_mipmap (GDK_GL_TEXTURE (texture));
offscreen->texture_id = gsk_gl_driver_load_texture (job->driver, texture, ensure_mipmap);
init_full_texture_region (offscreen);
offscreen->has_mipmap = ensure_mipmap;
if (gl_texture && offscreen->texture_id == gdk_gl_texture_get_id (gl_texture))
offscreen->sync = gdk_gl_texture_get_sync (gl_texture);
if (GDK_IS_GL_TEXTURE (texture) &&
offscreen->texture_id == gdk_gl_texture_get_id (GDK_GL_TEXTURE (texture)))
offscreen->sync = gdk_gl_texture_get_sync (GDK_GL_TEXTURE (texture));
}
}

View File

@@ -0,0 +1,49 @@
// VERTEX_SHADER:
// nv12.glsl
void main() {
gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
vUv = vec2(aUv.x, aUv.y);
}
// FRAGMENT_SHADER:
// nv12.glsl
uniform sampler2D u_source2;
vec4 yuv_to_rgb(vec4 yuv)
{
vec4 res;
float Y = 1.16438356 * (yuv.x - 0.0625);
float su = yuv.y - 0.5;
float sv = yuv.z - 0.5;
res.r = Y + 1.59602678 * sv;
res.g = Y - 0.39176229 * su - 0.81296764 * sv;
res.b = Y + 2.01723214 * su;
res.rgb *= yuv.w;
res.a = yuv.w;
return res;
}
/* This shader converts 2-plane yuv (DRM_FORMAT_NV12 or DRM_FORMAT_P010)
* into rgb. It assumes that the two planes have been imported separately,
* the first one as R texture, the second one as RG.
*/
void main() {
vec4 y = GskTexture(u_source, vUv);
vec4 uv = GskTexture(u_source2, vUv);
vec4 yuv;
yuv.x = y.x;
yuv.yz = uv.xy;
yuv.w = 1.0;
gskSetOutputColor(yuv_to_rgb(yuv));
}

View File

@@ -0,0 +1,51 @@
// VERTEX_SHADER:
// y_uv_to_rgba.glsl
void main() {
gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
vUv = vec2(aUv.x, aUv.y);
}
// FRAGMENT_SHADER:
// y_uv_to_rgba.glsl
uniform sampler2D u_source2;
uniform sampler2D u_source3;
vec4 yuv_to_rgb(vec4 yuv)
{
vec4 res;
float Y = 1.16438356 * (yuv.x - 0.0625);
float su = yuv.y - 0.5;
float sv = yuv.z - 0.5;
res.r = Y + 1.59602678 * sv;
res.g = Y - 0.39176229 * su - 0.81296764 * sv;
res.b = Y + 2.01723214 * su;
res.rgb *= yuv.w;
res.a = yuv.w;
return res;
}
/* This shader converts 3-plane yuv (DRM_FORMAT_YUY420) into rgb.
*/
void main() {
vec4 y = GskTexture(u_source, vUv);
vec4 u = GskTexture(u_source2, vUv);
vec4 v = GskTexture(u_source3, vUv);
vec4 yuv;
yuv.x = y.x;
yuv.y = u.x;
yuv.z = v.x;
yuv.w = 1.0;
gskSetOutputColor(yuv_to_rgb(yuv));
}

View File

@@ -0,0 +1,49 @@
// VERTEX_SHADER:
// y_xuxv_to_rgba.glsl
void main() {
gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
vUv = vec2(aUv.x, aUv.y);
}
// FRAGMENT_SHADER:
// y_xuxv_to_rgba.glsl
uniform sampler2D u_source2;
vec4 yuv_to_rgb(vec4 yuv)
{
vec4 res;
float Y = 1.16438356 * (yuv.x - 0.0625);
float su = yuv.y - 0.5;
float sv = yuv.z - 0.5;
res.r = Y + 1.59602678 * sv;
res.g = Y - 0.39176229 * su - 0.81296764 * sv;
res.b = Y + 2.01723214 * su;
res.rgb *= yuv.w;
res.a = yuv.w;
return res;
}
/* This shader converts single-plane yuv (DRM_FORMAT_YUYV) into rgb.
* It assumes that the buffer has been imported twice - once as RG
* texture with full size, and once as RGBA textures with half the
* width (to account for the subsampling).
*/
void main() {
vec4 y = GskTexture(u_source, vUv);
vec4 uv = GskTexture(u_source2, vUv);
vec4 yuv;
yuv.x = y.x;
yuv.yz = uv.yw;
yuv.w = 1.0;
gskSetOutputColor(yuv_to_rgb(yuv));
}

View File

@@ -20,6 +20,9 @@ gsk_private_gl_shaders = [
'gl/resources/custom.glsl',
'gl/resources/filled_border.glsl',
'gl/resources/mask.glsl',
'gl/resources/yuyv.glsl',
'gl/resources/nv12.glsl',
'gl/resources/yuv420.glsl',
]
gsk_public_sources = files([