Compare commits

...

1 Commits

Author SHA1 Message Date
Matthias Clasen
e63b69a589 dmabuf:Support upside-down dmabufs
Add a y-invert flag to GdkDmabufTextureBuilder, and handle it
when passing dmabufs to the compositor, when downloading them,
and when using them in GL.

Fixes: #6258
2023-12-09 08:34:44 +04:00
7 changed files with 161 additions and 17 deletions

View File

@@ -45,9 +45,40 @@ struct _GdkDrmFormatInfo
gsize height,
const GdkDmabuf *dmabuf,
const guchar *src_datas[GDK_DMABUF_MAX_PLANES],
gsize sizes[GDK_DMABUF_MAX_PLANES]);
gsize sizes[GDK_DMABUF_MAX_PLANES],
gboolean y_invert);
};
static inline void
flip_upside_down (guchar *dst_data,
gsize dst_stride,
GdkMemoryFormat dst_format,
gsize width,
gsize height)
{
guchar *tmp;
guint bpp;
bpp = gdk_memory_format_bytes_per_pixel (dst_format);
tmp = g_malloc (dst_stride);
g_assert (dst_stride >= bpp * width);
for (gsize i = 0 ; i < height / 2; i++)
{
guchar *row1, *row2;
row1 = dst_data + i * dst_stride;
row2 = dst_data + (height - 1 - i) * dst_stride;
memcpy (tmp, row1, bpp * width);
memcpy (row1, row2, bpp * width);
memcpy (row2, tmp, bpp * width);
}
g_free (tmp);
}
static void
download_memcpy (guchar *dst_data,
gsize dst_stride,
@@ -56,7 +87,8 @@ download_memcpy (guchar *dst_data,
gsize height,
const GdkDmabuf *dmabuf,
const guchar *src_datas[GDK_DMABUF_MAX_PLANES],
gsize sizes[GDK_DMABUF_MAX_PLANES])
gsize sizes[GDK_DMABUF_MAX_PLANES],
gboolean y_invert)
{
const guchar *src_data;
gsize src_stride;
@@ -67,14 +99,15 @@ download_memcpy (guchar *dst_data,
src_data = src_datas[0] + dmabuf->planes[0].offset;
g_return_if_fail (sizes[0] >= dmabuf->planes[0].offset + (height - 1) * dst_stride + width * bpp);
if (dst_stride == src_stride)
if (dst_stride == src_stride && !y_invert)
memcpy (dst_data, src_data, (height - 1) * dst_stride + width * bpp);
else
{
gsize i;
for (i = 0; i < height; i++)
memcpy (dst_data + i * dst_stride, src_data + i * src_stride, width * bpp);
for (gsize i = 0; i < height; i++)
{
gsize src_row = y_invert ? height - 1 - i : i;
memcpy (dst_data + i * dst_stride, src_data + src_row * src_stride, width * bpp);
}
}
}
@@ -86,7 +119,8 @@ download_memcpy_3_1 (guchar *dst_data,
gsize height,
const GdkDmabuf *dmabuf,
const guchar *src_datas[GDK_DMABUF_MAX_PLANES],
gsize sizes[GDK_DMABUF_MAX_PLANES])
gsize sizes[GDK_DMABUF_MAX_PLANES],
gboolean y_invert)
{
guint a;
guchar *dst_row;
@@ -95,7 +129,7 @@ download_memcpy_3_1 (guchar *dst_data,
g_assert (dmabuf->n_planes == 2);
download_memcpy (dst_data, dst_stride, dst_format, width, height, dmabuf, src_datas, sizes);
download_memcpy (dst_data, dst_stride, dst_format, width, height, dmabuf, src_datas, sizes, y_invert);
switch ((int)dst_format)
{
@@ -178,11 +212,13 @@ download_nv12 (guchar *dst_data,
gsize height,
const GdkDmabuf *dmabuf,
const guchar *src_data[GDK_DMABUF_MAX_PLANES],
gsize sizes[GDK_DMABUF_MAX_PLANES])
gsize sizes[GDK_DMABUF_MAX_PLANES],
gboolean y_invert)
{
const guchar *y_data, *uv_data;
gsize x, y, y_stride, uv_stride;
gsize U, V, X_SUB, Y_SUB;
guchar *orig_dst_data = dst_data;
switch (dmabuf->fourcc)
{
@@ -233,6 +269,9 @@ download_nv12 (guchar *dst_data,
y_data += Y_SUB * y_stride;
uv_data += uv_stride;
}
if (y_invert)
flip_upside_down (orig_dst_data, dst_stride, dst_format, width, height);
}
static void
@@ -243,11 +282,13 @@ download_yuv_3 (guchar *dst_data,
gsize height,
const GdkDmabuf *dmabuf,
const guchar *src_data[GDK_DMABUF_MAX_PLANES],
gsize sizes[GDK_DMABUF_MAX_PLANES])
gsize sizes[GDK_DMABUF_MAX_PLANES],
gboolean y_invert)
{
const guchar *y_data, *u_data, *v_data;
gsize x, y, y_stride, u_stride, v_stride;
gsize U, V, X_SUB, Y_SUB;
guchar *orig_dst_data = dst_data;
switch (dmabuf->fourcc)
{
@@ -314,6 +355,9 @@ download_yuv_3 (guchar *dst_data,
u_data += u_stride;
v_data += v_stride;
}
if (y_invert)
flip_upside_down (orig_dst_data, dst_stride, dst_format, width, height);
}
static void
@@ -324,11 +368,13 @@ download_yuyv (guchar *dst_data,
gsize height,
const GdkDmabuf *dmabuf,
const guchar *src_datas[GDK_DMABUF_MAX_PLANES],
gsize sizes[GDK_DMABUF_MAX_PLANES])
gsize sizes[GDK_DMABUF_MAX_PLANES],
gboolean y_invert)
{
const guchar *src_data;
gsize x, y, src_stride;
gsize Y1, Y2, U, V;
guchar *orig_dst_data = dst_data;
switch (dmabuf->fourcc)
{
@@ -367,6 +413,9 @@ download_yuyv (guchar *dst_data,
dst_data += dst_stride;
src_data += src_stride;
}
if (y_invert)
flip_upside_down (orig_dst_data, dst_stride, dst_format, width, height);
}
static const GdkDrmFormatInfo supported_formats[] = {
@@ -703,12 +752,15 @@ gdk_dmabuf_direct_downloader_do_download (const GdkDmabufDownloader *downloader,
{
const GdkDrmFormatInfo *info;
const GdkDmabuf *dmabuf;
gboolean y_invert;
const guchar *src_data[GDK_DMABUF_MAX_PLANES];
gsize sizes[GDK_DMABUF_MAX_PLANES];
gsize needs_unmap[GDK_DMABUF_MAX_PLANES] = { FALSE, };
gsize i, j;
dmabuf = gdk_dmabuf_texture_get_dmabuf (GDK_DMABUF_TEXTURE (texture));
y_invert = gdk_dmabuf_texture_get_y_invert (GDK_DMABUF_TEXTURE (texture));
info = get_drm_format_info (dmabuf->fourcc);
g_return_if_fail (info && info->download);
@@ -759,7 +811,8 @@ gdk_dmabuf_direct_downloader_do_download (const GdkDmabufDownloader *downloader,
gdk_texture_get_height (texture),
dmabuf,
src_data,
sizes);
sizes,
y_invert);
out:
for (i = 0; i < dmabuf->n_planes; i++)

View File

@@ -51,6 +51,8 @@ struct _GdkDmabufTexture
GDestroyNotify destroy;
gpointer data;
gboolean y_invert;
};
struct _GdkDmabufTextureClass
@@ -116,6 +118,12 @@ gdk_dmabuf_texture_get_dmabuf (GdkDmabufTexture *self)
return &self->dmabuf;
}
gboolean
gdk_dmabuf_texture_get_y_invert (GdkDmabufTexture *self)
{
return self->y_invert;
}
GdkTexture *
gdk_dmabuf_texture_new_from_builder (GdkDmabufTextureBuilder *builder,
GDestroyNotify destroy,
@@ -184,6 +192,7 @@ gdk_dmabuf_texture_new_from_builder (GdkDmabufTextureBuilder *builder,
self->dmabuf = dmabuf;
self->destroy = destroy;
self->data = data;
self->y_invert = gdk_dmabuf_texture_builder_get_y_invert (builder);
update_texture = gdk_dmabuf_texture_builder_get_update_texture (builder);
if (update_texture)

View File

@@ -37,6 +37,7 @@ struct _GdkDmabufTextureBuilder
unsigned int width;
unsigned int height;
gboolean premultiplied;
gboolean y_invert;
GdkDmabuf dmabuf;
@@ -123,6 +124,7 @@ enum
PROP_MODIFIER,
PROP_PREMULTIPLIED,
PROP_N_PLANES,
PROP_Y_INVERT,
PROP_UPDATE_REGION,
PROP_UPDATE_TEXTURE,
@@ -182,6 +184,10 @@ gdk_dmabuf_texture_builder_get_property (GObject *object,
g_value_set_uint (value, self->dmabuf.n_planes);
break;
case PROP_Y_INVERT:
g_value_set_boolean (value, self->y_invert);
break;
case PROP_UPDATE_REGION:
g_value_set_boxed (value, self->update_region);
break;
@@ -234,6 +240,10 @@ gdk_dmabuf_texture_builder_set_property (GObject *object,
gdk_dmabuf_texture_builder_set_n_planes (self, g_value_get_uint (value));
break;
case PROP_Y_INVERT:
gdk_dmabuf_texture_builder_set_y_invert (self, g_value_get_boolean (value));
break;
case PROP_UPDATE_REGION:
gdk_dmabuf_texture_builder_set_update_region (self, g_value_get_boxed (value));
break;
@@ -346,6 +356,18 @@ gdk_dmabuf_texture_builder_class_init (GdkDmabufTextureBuilderClass *klass)
1, GDK_DMABUF_MAX_PLANES, 1,
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
/**
* GdkDmabufTextureBuilder:y-invert: (attributes org.gtk.Property.get=gdk_dmabuf_texture_builder_get_y_invert org.gtk.Property.set=gdk_dmabuf_texture_builder_set_y_invert)
*
* Whether the texture is upside-down.
*
* Since: 4.14
*/
properties[PROP_Y_INVERT] =
g_param_spec_boolean ("y-invert", NULL, NULL,
FALSE,
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
/**
* GdkDmabufTextureBuilder:update-region: (attributes org.gtk.Property.get=gdk_dmabuf_texture_builder_get_update_region org.gtk.Property.set=gdk_dmabuf_texture_builder_set_update_region)
*
@@ -842,6 +864,47 @@ gdk_dmabuf_texture_builder_set_offset (GdkDmabufTextureBuilder *self,
self->dmabuf.planes[plane].offset = offset;
}
/**
* gdk_dmabuf_texture_builder_get_y_invert:
* @self: a `GdkDmabufTextureBuilder`
*
* Gets whether the texture is upside-down.
*
* Returns: whether the texture is upside-down.
*
* Since: 4.14
*/
gboolean
gdk_dmabuf_texture_builder_get_y_invert (GdkDmabufTextureBuilder *self)
{
g_return_val_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self), FALSE);
return self->y_invert;
}
/**
* gdk_dmabuf_texture_builder_set_y_invert:
* @self: a `GdkDmabufTextureBuilder`
* @y_invert: whether the texture is upside-down
*
* Sets whether the texture is upside-down.
*
* Since: 4.14
*/
void
gdk_dmabuf_texture_builder_set_y_invert (GdkDmabufTextureBuilder *self,
gboolean y_invert)
{
g_return_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self));
if (self->y_invert == y_invert)
return;
self->y_invert = y_invert;
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_Y_INVERT]);
}
/**
* gdk_dmabuf_texture_builder_get_update_texture: (attributes org.gtk.Method.get_property=update-texture)
* @self: a `GdkDmabufTextureBuilder`

View File

@@ -100,6 +100,12 @@ void gdk_dmabuf_texture_builder_set_offset (GdkDmabufT
unsigned int plane,
unsigned int offset);
GDK_AVAILABLE_IN_4_14
gboolean gdk_dmabuf_texture_builder_get_y_invert (GdkDmabufTextureBuilder *self) G_GNUC_PURE;
GDK_AVAILABLE_IN_4_14
void gdk_dmabuf_texture_builder_set_y_invert (GdkDmabufTextureBuilder *self,
gboolean y_invert);
GDK_AVAILABLE_IN_4_14
GdkTexture * gdk_dmabuf_texture_builder_get_update_texture (GdkDmabufTextureBuilder *self) G_GNUC_PURE;
GDK_AVAILABLE_IN_4_14

View File

@@ -16,6 +16,7 @@ GdkTexture * gdk_dmabuf_texture_new_from_builder (GdkDmabufTextureBui
GdkDisplay * gdk_dmabuf_texture_get_display (GdkDmabufTexture *self);
const GdkDmabuf * gdk_dmabuf_texture_get_dmabuf (GdkDmabufTexture *self);
gboolean gdk_dmabuf_texture_get_y_invert (GdkDmabufTexture *self);
G_END_DECLS

View File

@@ -106,8 +106,11 @@ get_wl_buffer (GdkWaylandSubsurface *self,
struct wl_buffer *buffer;
CreateBufferData cd = { NULL, FALSE };
struct wl_event_queue *event_queue;
uint32_t flags = 0;
dmabuf = gdk_dmabuf_texture_get_dmabuf (GDK_DMABUF_TEXTURE (texture));
if (gdk_dmabuf_texture_get_y_invert (GDK_DMABUF_TEXTURE (texture)))
flags = ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_Y_INVERT;
params = zwp_linux_dmabuf_v1_create_params (display->linux_dmabuf);
@@ -130,7 +133,7 @@ get_wl_buffer (GdkWaylandSubsurface *self,
gdk_texture_get_width (texture),
gdk_texture_get_height (texture),
dmabuf->fourcc,
0);
flags);
while (!cd.done)
gdk_wayland_display_dispatch_queue (GDK_DISPLAY (display), event_queue);

View File

@@ -772,7 +772,8 @@ draw_rect (GskGLCommandQueue *command_queue,
float min_x,
float min_y,
float max_x,
float max_y)
float max_y,
gboolean y_invert)
{
GskGLDrawVertex *vertices = gsk_gl_command_queue_add_vertices (command_queue);
float min_u = 0;
@@ -781,6 +782,12 @@ draw_rect (GskGLCommandQueue *command_queue,
float max_v = 0;
guint16 c = FP16_ZERO;
if (y_invert)
{
min_v = 0;
max_v = 1;
}
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 } };
@@ -807,6 +814,7 @@ gsk_gl_driver_import_dmabuf_texture (GskGLDriver *self,
GskGLRenderTarget *render_target;
guint prev_fbo;
gboolean external;
gboolean y_invert;
gdk_gl_context_make_current (context);
@@ -822,6 +830,7 @@ gsk_gl_driver_import_dmabuf_texture (GskGLDriver *self,
}
dmabuf = gdk_dmabuf_texture_get_dmabuf (texture);
y_invert = gdk_dmabuf_texture_get_y_invert (texture);
texture_id = gdk_gl_context_import_dmabuf (context,
width, height,
@@ -830,7 +839,7 @@ gsk_gl_driver_import_dmabuf_texture (GskGLDriver *self,
if (texture_id == 0)
return 0;
if (!external)
if (!external && !y_invert)
return texture_id;
gsk_gl_driver_autorelease_texture (self, texture_id);
@@ -853,7 +862,7 @@ gsk_gl_driver_import_dmabuf_texture (GskGLDriver *self,
UNIFORM_EXTERNAL_SOURCE, 0,
GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE0, texture_id);
draw_rect (self->command_queue, 0, 0, width, height);
draw_rect (self->command_queue, 0, 0, width, height, y_invert);
gsk_gl_command_queue_end_draw (self->command_queue);
}