gtk/gdk/gdkdmabuf.c
Benjamin Otte 9581d060d2 dmabuf: Fix disjoint detection
According to the Mesa developers, the correct way to determine
disjointness is to check the actual inode of the fd because dup()ing can
cause these duplications to happen when planes are carelessly copied or
when planes are sent over dbus or other unix sockets.

Related: https://bugs.webkit.org/show_bug.cgi?id=267578
2024-01-30 15:19:34 +01:00

2375 lines
59 KiB
C

/* gdkdmabuf.c
*
* Copyright 2023 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "gdkdmabufprivate.h"
#include "gdkdebugprivate.h"
#include "gdkdmabuffourccprivate.h"
#include "gdkdmabuftextureprivate.h"
#include "gdkmemoryformatprivate.h"
#ifdef HAVE_DMABUF
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <linux/dma-buf.h>
#include <epoxy/egl.h>
typedef struct _GdkDrmFormatInfo GdkDrmFormatInfo;
struct _GdkDrmFormatInfo
{
guint32 fourcc;
GdkMemoryFormat memory_format;
gboolean is_yuv;
void (* download) (guchar *dst_data,
gsize dst_stride,
GdkMemoryFormat dst_format,
gsize width,
gsize height,
const GdkDmabuf *dmabuf,
const guchar *src_datas[GDK_DMABUF_MAX_PLANES],
gsize sizes[GDK_DMABUF_MAX_PLANES]);
#ifdef GDK_RENDERING_VULKAN
struct {
VkFormat format;
VkComponentMapping swizzle;
} vk;
#endif
};
static void
download_memcpy (guchar *dst_data,
gsize dst_stride,
GdkMemoryFormat dst_format,
gsize width,
gsize height,
const GdkDmabuf *dmabuf,
const guchar *src_datas[GDK_DMABUF_MAX_PLANES],
gsize sizes[GDK_DMABUF_MAX_PLANES])
{
const guchar *src_data;
gsize src_stride;
guint bpp;
bpp = gdk_memory_format_bytes_per_pixel (dst_format);
src_stride = dmabuf->planes[0].stride;
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)
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);
}
}
static void
download_memcpy_3_1 (guchar *dst_data,
gsize dst_stride,
GdkMemoryFormat dst_format,
gsize width,
gsize height,
const GdkDmabuf *dmabuf,
const guchar *src_datas[GDK_DMABUF_MAX_PLANES],
gsize sizes[GDK_DMABUF_MAX_PLANES])
{
guint a;
guchar *dst_row;
const guchar *src_data, *src_row;
gsize src_stride;
g_assert (dmabuf->n_planes == 2);
download_memcpy (dst_data, dst_stride, dst_format, width, height, dmabuf, src_datas, sizes);
switch ((int)dst_format)
{
case GDK_MEMORY_A8R8G8B8:
case GDK_MEMORY_A8R8G8B8_PREMULTIPLIED:
case GDK_MEMORY_A8B8G8R8:
case GDK_MEMORY_A8B8G8R8_PREMULTIPLIED:
a = 0;
break;
case GDK_MEMORY_R8G8B8A8:
case GDK_MEMORY_R8G8B8A8_PREMULTIPLIED:
case GDK_MEMORY_B8G8R8A8:
case GDK_MEMORY_B8G8R8A8_PREMULTIPLIED:
a = 3;
break;
default:
g_assert_not_reached ();
}
src_stride = dmabuf->planes[1].stride;
src_data = src_datas[1];
for (gsize y = 0; y < height; y++)
{
dst_row = dst_data + y * dst_stride;
src_row = src_data + y * src_stride;
for (gsize x = 0; x < width; x++)
dst_row[4 * x + a] = src_row[x];
}
}
typedef struct _YUVCoefficients YUVCoefficients;
struct _YUVCoefficients
{
int v_to_r;
int u_to_g;
int v_to_g;
int u_to_b;
};
/* multiplied by 65536 */
//static const YUVCoefficients itu601_narrow = { 104597, -25675, -53279, 132201 };
static const YUVCoefficients itu601_wide = { 74711, -25864, -38050, 133176 };
static inline void
get_uv_values (const YUVCoefficients *coeffs,
guint8 u,
guint8 v,
int *out_r,
int *out_g,
int *out_b)
{
int u2 = (int) u - 127;
int v2 = (int) v - 127;
*out_r = coeffs->v_to_r * v2;
*out_g = coeffs->u_to_g * u2 + coeffs->v_to_g * v2;
*out_b = coeffs->u_to_b * u2;
}
static inline void
set_rgb_values (guint8 rgb[3],
guint8 y,
int r,
int g,
int b)
{
int y2 = y * 65536;
rgb[0] = CLAMP ((y2 + r) >> 16, 0, 255);
rgb[1] = CLAMP ((y2 + g) >> 16, 0, 255);
rgb[2] = CLAMP ((y2 + b) >> 16, 0, 255);
}
static void
download_nv12 (guchar *dst_data,
gsize dst_stride,
GdkMemoryFormat dst_format,
gsize width,
gsize height,
const GdkDmabuf *dmabuf,
const guchar *src_data[GDK_DMABUF_MAX_PLANES],
gsize sizes[GDK_DMABUF_MAX_PLANES])
{
const guchar *y_data, *uv_data;
gsize x, y, y_stride, uv_stride;
gsize U, V, X_SUB, Y_SUB;
switch (dmabuf->fourcc)
{
case DRM_FORMAT_NV12:
U = 0; V = 1; X_SUB = 2; Y_SUB = 2;
break;
case DRM_FORMAT_NV21:
U = 1; V = 0; X_SUB = 2; Y_SUB = 2;
break;
case DRM_FORMAT_NV16:
U = 0; V = 1; X_SUB = 2; Y_SUB = 1;
break;
case DRM_FORMAT_NV61:
U = 1; V = 0; X_SUB = 2; Y_SUB = 1;
break;
case DRM_FORMAT_NV24:
U = 0; V = 1; X_SUB = 1; Y_SUB = 1;
break;
case DRM_FORMAT_NV42:
U = 1; V = 0; X_SUB = 1; Y_SUB = 1;
break;
default:
g_assert_not_reached ();
return;
}
y_stride = dmabuf->planes[0].stride;
y_data = src_data[0] + dmabuf->planes[0].offset;
g_return_if_fail (sizes[0] >= dmabuf->planes[0].offset + height * y_stride);
uv_stride = dmabuf->planes[1].stride;
uv_data = src_data[1] + dmabuf->planes[1].offset;
g_return_if_fail (sizes[1] >= dmabuf->planes[1].offset + (height + Y_SUB - 1) / Y_SUB * uv_stride);
for (y = 0; y < height; y += Y_SUB)
{
for (x = 0; x < width; x += X_SUB)
{
int r, g, b;
gsize xs, ys;
get_uv_values (&itu601_wide, uv_data[x / X_SUB * 2 + U], uv_data[x / X_SUB * 2 + V], &r, &g, &b);
for (ys = 0; ys < Y_SUB && y + ys < height; ys++)
for (xs = 0; xs < X_SUB && x + xs < width; xs++)
set_rgb_values (&dst_data[3 * (x + xs) + dst_stride * ys], y_data[x + xs + y_stride * ys], r, g, b);
}
dst_data += Y_SUB * dst_stride;
y_data += Y_SUB * y_stride;
uv_data += uv_stride;
}
}
static void
download_yuv_3 (guchar *dst_data,
gsize dst_stride,
GdkMemoryFormat dst_format,
gsize width,
gsize height,
const GdkDmabuf *dmabuf,
const guchar *src_data[GDK_DMABUF_MAX_PLANES],
gsize sizes[GDK_DMABUF_MAX_PLANES])
{
const guchar *y_data, *u_data, *v_data;
gsize x, y, y_stride, u_stride, v_stride;
gsize U, V, X_SUB, Y_SUB;
switch (dmabuf->fourcc)
{
case DRM_FORMAT_YUV410:
U = 1; V = 2; X_SUB = 4; Y_SUB = 4;
break;
case DRM_FORMAT_YVU410:
U = 2; V = 1; X_SUB = 4; Y_SUB = 4;
break;
case DRM_FORMAT_YUV411:
U = 1; V = 2; X_SUB = 4; Y_SUB = 1;
break;
case DRM_FORMAT_YVU411:
U = 2; V = 1; X_SUB = 4; Y_SUB = 1;
break;
case DRM_FORMAT_YUV420:
U = 1; V = 2; X_SUB = 2; Y_SUB = 2;
break;
case DRM_FORMAT_YVU420:
U = 2; V = 1; X_SUB = 2; Y_SUB = 2;
break;
case DRM_FORMAT_YUV422:
U = 1; V = 2; X_SUB = 2; Y_SUB = 1;
break;
case DRM_FORMAT_YVU422:
U = 2; V = 1; X_SUB = 2; Y_SUB = 1;
break;
case DRM_FORMAT_YUV444:
U = 1; V = 2; X_SUB = 1; Y_SUB = 1;
break;
case DRM_FORMAT_YVU444:
U = 2; V = 1; X_SUB = 1; Y_SUB = 1;
break;
default:
g_assert_not_reached ();
return;
}
y_stride = dmabuf->planes[0].stride;
y_data = src_data[0] + dmabuf->planes[0].offset;
g_return_if_fail (sizes[0] >= dmabuf->planes[0].offset + height * y_stride);
u_stride = dmabuf->planes[U].stride;
u_data = src_data[U] + dmabuf->planes[U].offset;
g_return_if_fail (sizes[U] >= dmabuf->planes[U].offset + (height + Y_SUB - 1) / Y_SUB * u_stride);
v_stride = dmabuf->planes[V].stride;
v_data = src_data[V] + dmabuf->planes[V].offset;
g_return_if_fail (sizes[V] >= dmabuf->planes[V].offset + (height + Y_SUB - 1) / Y_SUB * v_stride);
for (y = 0; y < height; y += Y_SUB)
{
for (x = 0; x < width; x += X_SUB)
{
int r, g, b;
gsize xs, ys;
get_uv_values (&itu601_wide, u_data[x / X_SUB], v_data[x / X_SUB], &r, &g, &b);
for (ys = 0; ys < Y_SUB && y + ys < height; ys++)
for (xs = 0; xs < X_SUB && x + xs < width; xs++)
set_rgb_values (&dst_data[3 * (x + xs) + dst_stride * ys], y_data[x + xs + y_stride * ys], r, g, b);
}
dst_data += Y_SUB * dst_stride;
y_data += Y_SUB * y_stride;
u_data += u_stride;
v_data += v_stride;
}
}
static void
download_yuyv (guchar *dst_data,
gsize dst_stride,
GdkMemoryFormat dst_format,
gsize width,
gsize height,
const GdkDmabuf *dmabuf,
const guchar *src_datas[GDK_DMABUF_MAX_PLANES],
gsize sizes[GDK_DMABUF_MAX_PLANES])
{
const guchar *src_data;
gsize x, y, src_stride;
gsize Y1, Y2, U, V;
switch (dmabuf->fourcc)
{
case DRM_FORMAT_YUYV:
Y1 = 0; U = 1; Y2 = 2; V = 3;
break;
case DRM_FORMAT_YVYU:
Y1 = 0; V = 1; Y2 = 2; U = 3;
break;
case DRM_FORMAT_UYVY:
U = 0; Y1 = 1; V = 2; Y2 = 3;
break;
case DRM_FORMAT_VYUY:
V = 0; Y1 = 1; U = 2; Y2 = 3;
break;
default:
g_assert_not_reached ();
return;
}
src_stride = dmabuf->planes[0].stride;
src_data = src_datas[0] + dmabuf->planes[0].offset;
g_return_if_fail (sizes[0] >= dmabuf->planes[0].offset + height * src_stride);
for (y = 0; y < height; y ++)
{
for (x = 0; x < width; x += 2)
{
int r, g, b;
get_uv_values (&itu601_wide, src_data[2 * x + U], src_data[2 * x + V], &r, &g, &b);
set_rgb_values (&dst_data[3 * x], src_data[2 * x + Y1], r, g, b);
if (x + 1 < width)
set_rgb_values (&dst_data[3 * (x + 1)], src_data[2 * x + Y2], r, g, b);
}
dst_data += dst_stride;
src_data += src_stride;
}
}
#define VULKAN_SWIZZLE(_R, _G, _B, _A) { VK_COMPONENT_SWIZZLE_ ## _R, VK_COMPONENT_SWIZZLE_ ## _G, VK_COMPONENT_SWIZZLE_ ## _B, VK_COMPONENT_SWIZZLE_ ## _A }
#define VULKAN_DEFAULT_SWIZZLE VULKAN_SWIZZLE (R, G, B, A)
static const GdkDrmFormatInfo supported_formats[] = {
#if 0
/* palette formats?! */
{
.fourcc = DRM_FORMAT_C1,
.memory_format = GDK_MEMORY_,
.is_yuv = FALSE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format =
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_C2,
.memory_format = GDK_MEMORY_,
.is_yuv = FALSE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format =
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_C4,
.memory_format = GDK_MEMORY_,
.is_yuv = FALSE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format =
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_C8,
.memory_format = GDK_MEMORY_,
.is_yuv = FALSE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format =
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
#endif
/* darkness */
{
.fourcc = DRM_FORMAT_D1,
.memory_format = GDK_MEMORY_G8,
.is_yuv = FALSE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_UNDEFINED,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_D2,
.memory_format = GDK_MEMORY_G8,
.is_yuv = FALSE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_UNDEFINED,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_D4,
.memory_format = GDK_MEMORY_G8,
.is_yuv = FALSE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_UNDEFINED,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_D8,
.memory_format = GDK_MEMORY_G8,
.is_yuv = FALSE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_UNDEFINED,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
/* red only - we treat this as gray */
{
.fourcc = DRM_FORMAT_R1,
.memory_format = GDK_MEMORY_G8,
.is_yuv = FALSE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_UNDEFINED,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_R2,
.memory_format = GDK_MEMORY_G8,
.is_yuv = FALSE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_UNDEFINED,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_R4,
.memory_format = GDK_MEMORY_G8,
.is_yuv = FALSE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_UNDEFINED,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_R8,
.memory_format = GDK_MEMORY_G8,
.is_yuv = FALSE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_R8_UNORM,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_R10,
.memory_format = GDK_MEMORY_G16,
.is_yuv = FALSE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_UNDEFINED, //VK_FORMAT_R16_UNORM,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_R12,
.memory_format = GDK_MEMORY_G16,
.is_yuv = FALSE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_UNDEFINED, //VK_FORMAT_R16_UNORM,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_R16,
.memory_format = GDK_MEMORY_G16,
.is_yuv = FALSE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_R16_UNORM,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
/* 2 channels - FIXME: Should this be gray + alpha? */
{
.fourcc = DRM_FORMAT_RG88,
.memory_format = GDK_MEMORY_R8G8B8,
.is_yuv = FALSE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_R8G8_UNORM,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_GR88,
.memory_format = GDK_MEMORY_R8G8B8,
.is_yuv = FALSE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_R8G8_UNORM,
.swizzle = VULKAN_SWIZZLE (G, R, B, A),
},
#endif
},
{
.fourcc = DRM_FORMAT_RG1616,
.memory_format = GDK_MEMORY_R16G16B16,
.is_yuv = FALSE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_R16G16_UNORM,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_GR1616,
.memory_format = GDK_MEMORY_R16G16B16,
.is_yuv = FALSE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_R16G16_UNORM,
.swizzle = VULKAN_SWIZZLE (G, R, B, A),
},
#endif
},
/* <8bit per channel RGB(A) */
{
.fourcc = DRM_FORMAT_RGB332,
.memory_format = GDK_MEMORY_B8G8R8,
.is_yuv = FALSE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_UNDEFINED,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_BGR233,
.memory_format = GDK_MEMORY_R8G8B8,
.is_yuv = FALSE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_UNDEFINED,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_XRGB4444,
.memory_format = GDK_MEMORY_B8G8R8,
.is_yuv = FALSE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_A4R4G4B4_UNORM_PACK16,
.swizzle = VULKAN_SWIZZLE (R, G, B, ONE),
},
#endif
},
{
.fourcc = DRM_FORMAT_XBGR4444,
.memory_format = GDK_MEMORY_R8G8B8,
.is_yuv = FALSE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_A4B4G4R4_UNORM_PACK16,
.swizzle = VULKAN_SWIZZLE (R, G, B, ONE),
},
#endif
},
{
.fourcc = DRM_FORMAT_RGBX4444,
.memory_format = GDK_MEMORY_B8G8R8,
.is_yuv = FALSE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_R4G4B4A4_UNORM_PACK16,
.swizzle = VULKAN_SWIZZLE (R, G, B, ONE),
},
#endif
},
{
.fourcc = DRM_FORMAT_BGRX4444,
.memory_format = GDK_MEMORY_R8G8B8,
.is_yuv = FALSE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_B4G4R4A4_UNORM_PACK16,
.swizzle = VULKAN_SWIZZLE (R, G, B, ONE),
},
#endif
},
{
.fourcc = DRM_FORMAT_ARGB4444,
.memory_format = GDK_MEMORY_B8G8R8A8_PREMULTIPLIED,
.is_yuv = FALSE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_A4R4G4B4_UNORM_PACK16,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_ABGR4444,
.memory_format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
.is_yuv = FALSE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_A4B4G4R4_UNORM_PACK16,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_RGBA4444,
.memory_format = GDK_MEMORY_A8B8G8R8_PREMULTIPLIED,
.is_yuv = FALSE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_R4G4B4A4_UNORM_PACK16,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_BGRA4444,
.memory_format = GDK_MEMORY_A8R8G8B8_PREMULTIPLIED,
.is_yuv = FALSE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_B4G4R4A4_UNORM_PACK16,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_XRGB1555,
.memory_format = GDK_MEMORY_B8G8R8,
.is_yuv = FALSE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_A1R5G5B5_UNORM_PACK16,
.swizzle = VULKAN_SWIZZLE (R, G, B, ONE),
},
#endif
},
{
.fourcc = DRM_FORMAT_XBGR1555,
.memory_format = GDK_MEMORY_R8G8B8,
.is_yuv = FALSE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_A1R5G5B5_UNORM_PACK16, // requires VK_KHR_maintenance5: VK_FORMAT_A1B5G5R5_UNORM_PACK16_KHR
.swizzle = VULKAN_SWIZZLE (B, G, R, ONE),
},
#endif
},
{
.fourcc = DRM_FORMAT_RGBX5551,
.memory_format = GDK_MEMORY_B8G8R8,
.is_yuv = FALSE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_R5G5B5A1_UNORM_PACK16,
.swizzle = VULKAN_SWIZZLE (R, G, B, ONE),
},
#endif
},
{
.fourcc = DRM_FORMAT_BGRX5551,
.memory_format = GDK_MEMORY_R8G8B8,
.is_yuv = FALSE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_B5G5R5A1_UNORM_PACK16,
.swizzle = VULKAN_SWIZZLE (R, G, B, ONE),
},
#endif
},
{
.fourcc = DRM_FORMAT_ARGB1555,
.memory_format = GDK_MEMORY_B8G8R8A8_PREMULTIPLIED,
.is_yuv = FALSE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_A1R5G5B5_UNORM_PACK16,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_ABGR1555,
.memory_format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
.is_yuv = FALSE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_A1R5G5B5_UNORM_PACK16, // requires VK_KHR_maintenance5: VK_FORMAT_A1B5G5R5_UNORM_PACK16_KHR
.swizzle = VULKAN_SWIZZLE (B, G, R, A),
},
#endif
},
{
.fourcc = DRM_FORMAT_RGBA5551,
.memory_format = GDK_MEMORY_A8B8G8R8_PREMULTIPLIED,
.is_yuv = FALSE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_R5G5B5A1_UNORM_PACK16,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_BGRA5551,
.memory_format = GDK_MEMORY_A8R8G8B8_PREMULTIPLIED,
.is_yuv = FALSE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_B5G5R5A1_UNORM_PACK16,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_RGB565,
.memory_format = GDK_MEMORY_B8G8R8,
.is_yuv = FALSE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_R5G6B5_UNORM_PACK16,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_BGR565,
.memory_format = GDK_MEMORY_R8G8B8,
.is_yuv = FALSE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_B5G6R5_UNORM_PACK16,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
/* 8bit RGB */
{
.fourcc = DRM_FORMAT_RGB888,
.memory_format = GDK_MEMORY_R8G8B8,
.is_yuv = FALSE,
.download = download_memcpy,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_B8G8R8_UNORM,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_BGR888,
.memory_format = GDK_MEMORY_B8G8R8,
.is_yuv = FALSE,
.download = download_memcpy,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_R8G8B8_UNORM,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
/* 8bit RGBA */
{
.fourcc = DRM_FORMAT_BGRA8888,
.memory_format = GDK_MEMORY_A8R8G8B8_PREMULTIPLIED,
.is_yuv = FALSE,
.download = download_memcpy,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_R8G8B8A8_UNORM,
.swizzle = VULKAN_SWIZZLE (G, B, A, R),
},
#endif
},
{
.fourcc = DRM_FORMAT_ABGR8888,
.memory_format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
.is_yuv = FALSE,
.download = download_memcpy,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_R8G8B8A8_UNORM,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_ARGB8888,
.memory_format = GDK_MEMORY_B8G8R8A8_PREMULTIPLIED,
.is_yuv = FALSE,
.download = download_memcpy,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_B8G8R8A8_UNORM,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_RGBA8888,
.memory_format = GDK_MEMORY_A8B8G8R8_PREMULTIPLIED,
.is_yuv = FALSE,
.download = download_memcpy,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_R8G8B8A8_UNORM,
.swizzle = VULKAN_SWIZZLE (A, B, G, R),
},
#endif
},
{
.fourcc = DRM_FORMAT_BGRX8888,
.memory_format = GDK_MEMORY_X8R8G8B8,
.is_yuv = FALSE,
.download = download_memcpy,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_R8G8B8A8_UNORM,
.swizzle = VULKAN_SWIZZLE (G, B, A, ONE),
},
#endif
},
{
.fourcc = DRM_FORMAT_XBGR8888,
.memory_format = GDK_MEMORY_R8G8B8X8,
.is_yuv = FALSE,
.download = download_memcpy,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_R8G8B8A8_UNORM,
.swizzle = VULKAN_SWIZZLE (R, G, B, ONE),
},
#endif
},
{
.fourcc = DRM_FORMAT_XRGB8888,
.memory_format = GDK_MEMORY_B8G8R8X8,
.is_yuv = FALSE,
.download = download_memcpy,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_B8G8R8A8_UNORM,
.swizzle = VULKAN_SWIZZLE (R, G, B, ONE),
},
#endif
},
{
.fourcc = DRM_FORMAT_RGBX8888,
.memory_format = GDK_MEMORY_X8B8G8R8,
.is_yuv = FALSE,
.download = download_memcpy,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_R8G8B8A8_UNORM,
.swizzle = VULKAN_SWIZZLE (A, B, G, ONE),
},
#endif
},
/* 10bit RGB(A) */
{
.fourcc = DRM_FORMAT_XRGB2101010,
.memory_format = GDK_MEMORY_R16G16B16,
.is_yuv = FALSE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_A2B10G10R10_UNORM_PACK32,
.swizzle = VULKAN_SWIZZLE (R, G, B, ONE),
},
#endif
},
{
.fourcc = DRM_FORMAT_XBGR2101010,
.memory_format = GDK_MEMORY_R16G16B16,
.is_yuv = FALSE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_A2B10G10R10_UNORM_PACK32,
.swizzle = VULKAN_SWIZZLE (R, G, B, ONE),
},
#endif
},
{
.fourcc = DRM_FORMAT_RGBX1010102,
.memory_format = GDK_MEMORY_R16G16B16,
.is_yuv = FALSE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_UNDEFINED,
.swizzle = VULKAN_SWIZZLE (R, G, B, ONE),
},
#endif
},
{
.fourcc = DRM_FORMAT_BGRX1010102,
.memory_format = GDK_MEMORY_R16G16B16,
.is_yuv = FALSE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_UNDEFINED,
.swizzle = VULKAN_SWIZZLE (R, G, B, ONE),
},
#endif
},
{
.fourcc = DRM_FORMAT_ARGB2101010,
.memory_format = GDK_MEMORY_R16G16B16A16_PREMULTIPLIED,
.is_yuv = FALSE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_A2B10G10R10_UNORM_PACK32,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_ABGR2101010,
.memory_format = GDK_MEMORY_R16G16B16A16_PREMULTIPLIED,
.is_yuv = FALSE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_A2B10G10R10_UNORM_PACK32,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_RGBA1010102,
.memory_format = GDK_MEMORY_R16G16B16A16_PREMULTIPLIED,
.is_yuv = FALSE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_UNDEFINED,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_BGRA1010102,
.memory_format = GDK_MEMORY_R16G16B16A16_PREMULTIPLIED,
.is_yuv = FALSE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_UNDEFINED,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
/* 16bit RGB(A) */
{
.fourcc = DRM_FORMAT_XRGB16161616,
.memory_format = GDK_MEMORY_R16G16B16,
.is_yuv = FALSE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_R16G16B16A16_UNORM,
.swizzle = VULKAN_SWIZZLE (B, G, R, ONE),
},
#endif
},
{
.fourcc = DRM_FORMAT_XBGR16161616,
.memory_format = GDK_MEMORY_R16G16B16,
.is_yuv = FALSE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_R16G16B16A16_UNORM,
.swizzle = VULKAN_SWIZZLE (R, G, B, ONE),
},
#endif
},
{
.fourcc = DRM_FORMAT_ARGB16161616,
.memory_format = GDK_MEMORY_R16G16B16A16_PREMULTIPLIED,
.is_yuv = FALSE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_R16G16B16A16_UNORM,
.swizzle = VULKAN_SWIZZLE (B, G, R, A),
},
#endif
},
{
.fourcc = DRM_FORMAT_ABGR16161616,
.memory_format = GDK_MEMORY_R16G16B16A16_PREMULTIPLIED,
.is_yuv = FALSE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_R16G16B16A16_UNORM,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_XRGB16161616F,
.memory_format = GDK_MEMORY_R16G16B16_FLOAT,
.is_yuv = FALSE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_R16G16B16A16_SFLOAT,
.swizzle = VULKAN_SWIZZLE (B, G, R, ONE),
},
#endif
},
{
.fourcc = DRM_FORMAT_XBGR16161616F,
.memory_format = GDK_MEMORY_R16G16B16_FLOAT,
.is_yuv = FALSE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_R16G16B16A16_SFLOAT,
.swizzle = VULKAN_SWIZZLE (R, G, B, ONE),
},
#endif
},
{
.fourcc = DRM_FORMAT_ARGB16161616F,
.memory_format = GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED,
.is_yuv = FALSE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_R16G16B16A16_SFLOAT,
.swizzle = VULKAN_SWIZZLE (B, G, R, A),
},
#endif
},
{
.fourcc = DRM_FORMAT_ABGR16161616F,
.memory_format = GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED,
.is_yuv = FALSE,
.download = download_memcpy,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_R16G16B16A16_SFLOAT,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_AXBXGXRX106106106106,
.memory_format = GDK_MEMORY_R16G16B16A16_PREMULTIPLIED,
.is_yuv = FALSE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_UNDEFINED, //VK_FORMAT_R16G16B16A16_SFLOAT,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
/* 1-plane YUV formats */
{
.fourcc = DRM_FORMAT_YUYV,
.memory_format = GDK_MEMORY_R8G8B8,
.is_yuv = TRUE,
.download = download_yuyv,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_G8B8G8R8_422_UNORM,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_YVYU,
.memory_format = GDK_MEMORY_R8G8B8,
.is_yuv = TRUE,
.download = download_yuyv,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_G8B8G8R8_422_UNORM,
.swizzle = VULKAN_SWIZZLE (B, G, R, A),
},
#endif
},
{
.fourcc = DRM_FORMAT_VYUY,
.memory_format = GDK_MEMORY_R8G8B8,
.is_yuv = TRUE,
.download = download_yuyv,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_B8G8R8G8_422_UNORM,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_UYVY,
.memory_format = GDK_MEMORY_R8G8B8,
.is_yuv = TRUE,
.download = download_yuyv,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_B8G8R8G8_422_UNORM,
.swizzle = VULKAN_SWIZZLE (B, G, R, A),
},
#endif
},
{
.fourcc = DRM_FORMAT_AYUV,
.memory_format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
.is_yuv = TRUE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_B8G8R8A8_UNORM,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_AVUY8888,
.memory_format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
.is_yuv = TRUE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_R8G8B8A8_UNORM,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_XYUV8888,
.memory_format = GDK_MEMORY_R8G8B8,
.is_yuv = TRUE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_B8G8R8A8_UNORM,
.swizzle = VULKAN_SWIZZLE (R, G, B, ONE),
},
#endif
},
{
.fourcc = DRM_FORMAT_XVUY8888,
.memory_format = GDK_MEMORY_R8G8B8,
.is_yuv = TRUE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_R8G8B8A8_UNORM,
.swizzle = VULKAN_SWIZZLE (R, G, B, ONE),
},
#endif
},
{
.fourcc = DRM_FORMAT_VUY888,
.memory_format = GDK_MEMORY_R8G8B8,
.is_yuv = TRUE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_R8G8B8_UNORM,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_VUY101010,
.memory_format = GDK_MEMORY_R16G16B16,
.is_yuv = TRUE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_UNDEFINED, /* NB: nonlinear-modifier only */
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_Y210,
.memory_format = GDK_MEMORY_R16G16B16,
.is_yuv = TRUE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_Y212,
.memory_format = GDK_MEMORY_R16G16B16,
.is_yuv = TRUE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_Y216,
.memory_format = GDK_MEMORY_R16G16B16,
.is_yuv = TRUE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_B16G16R16G16_422_UNORM,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_Y410,
.memory_format = GDK_MEMORY_R16G16B16,
.is_yuv = TRUE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_UNDEFINED,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_Y412,
.memory_format = GDK_MEMORY_R16G16B16,
.is_yuv = TRUE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_UNDEFINED,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_Y416,
.memory_format = GDK_MEMORY_R16G16B16,
.is_yuv = TRUE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_UNDEFINED,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_XVYU2101010,
.memory_format = GDK_MEMORY_R16G16B16,
.is_yuv = TRUE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_UNDEFINED,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_XVYU12_16161616,
.memory_format = GDK_MEMORY_R16G16B16,
.is_yuv = TRUE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_UNDEFINED,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_XVYU16161616,
.memory_format = GDK_MEMORY_R16G16B16,
.is_yuv = TRUE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_UNDEFINED,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
/* tiled YUV */
{
.fourcc = DRM_FORMAT_Y0L0,
.memory_format = GDK_MEMORY_R8G8B8,
.is_yuv = TRUE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_UNDEFINED,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_X0L0,
.memory_format = GDK_MEMORY_R8G8B8,
.is_yuv = TRUE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_UNDEFINED,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_Y0L2,
.memory_format = GDK_MEMORY_R16G16B16,
.is_yuv = TRUE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_UNDEFINED,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_X0L2,
.memory_format = GDK_MEMORY_R16G16B16,
.is_yuv = TRUE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_UNDEFINED,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
/* non-linear YUV */
{
.fourcc = DRM_FORMAT_YUV420_8BIT,
.memory_format = GDK_MEMORY_R8G8B8,
.is_yuv = TRUE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_UNDEFINED,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_YUV420_10BIT,
.memory_format = GDK_MEMORY_R16G16B16,
.is_yuv = TRUE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_UNDEFINED,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
/* 2 plane RGB + A */
{
.fourcc = DRM_FORMAT_BGRX8888_A8,
.memory_format = GDK_MEMORY_A8R8G8B8_PREMULTIPLIED,
.is_yuv = FALSE,
.download = download_memcpy_3_1,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_UNDEFINED,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_RGBX8888_A8,
.memory_format = GDK_MEMORY_A8B8G8R8_PREMULTIPLIED,
.is_yuv = FALSE,
.download = download_memcpy_3_1,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_UNDEFINED,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_XBGR8888_A8,
.memory_format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
.is_yuv = FALSE,
.download = download_memcpy_3_1,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_UNDEFINED,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_XRGB8888_A8,
.memory_format = GDK_MEMORY_B8G8R8A8_PREMULTIPLIED,
.is_yuv = FALSE,
.download = download_memcpy_3_1,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_UNDEFINED,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_RGB888_A8,
.memory_format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
.is_yuv = FALSE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_UNDEFINED,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_BGR888_A8,
.memory_format = GDK_MEMORY_B8G8R8A8_PREMULTIPLIED,
.is_yuv = FALSE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_UNDEFINED,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_RGB565_A8,
.memory_format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
.is_yuv = FALSE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_UNDEFINED,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_BGR565_A8,
.memory_format = GDK_MEMORY_B8G8R8A8_PREMULTIPLIED,
.is_yuv = FALSE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_UNDEFINED,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
/* 2-plane YUV formats */
{
.fourcc = DRM_FORMAT_NV12,
.memory_format = GDK_MEMORY_R8G8B8,
.is_yuv = TRUE,
.download = download_nv12,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_G8_B8R8_2PLANE_420_UNORM,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_NV21,
.memory_format = GDK_MEMORY_R8G8B8,
.is_yuv = TRUE,
.download = download_nv12,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_G8_B8R8_2PLANE_420_UNORM,
.swizzle = VULKAN_SWIZZLE (B, G, R, A),
},
#endif
},
{
.fourcc = DRM_FORMAT_NV16,
.memory_format = GDK_MEMORY_R8G8B8,
.is_yuv = TRUE,
.download = download_nv12,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_G8_B8R8_2PLANE_422_UNORM,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_NV61,
.memory_format = GDK_MEMORY_R8G8B8,
.is_yuv = TRUE,
.download = download_nv12,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_G8_B8R8_2PLANE_422_UNORM,
.swizzle = VULKAN_SWIZZLE (B, G, R, A),
},
#endif
},
{
.fourcc = DRM_FORMAT_NV24,
.memory_format = GDK_MEMORY_R8G8B8,
.is_yuv = TRUE,
.download = download_nv12,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_G8_B8R8_2PLANE_444_UNORM,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_NV42,
.memory_format = GDK_MEMORY_R8G8B8,
.is_yuv = TRUE,
.download = download_nv12,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_G8_B8R8_2PLANE_444_UNORM,
.swizzle = VULKAN_SWIZZLE (B, G, R, A),
},
#endif
},
{
.fourcc = DRM_FORMAT_NV15,
.memory_format = GDK_MEMORY_R16G16B16,
.is_yuv = TRUE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_UNDEFINED,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_P210,
.memory_format = GDK_MEMORY_R16G16B16,
.is_yuv = TRUE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_P010,
.memory_format = GDK_MEMORY_R16G16B16,
.is_yuv = TRUE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_P012,
.memory_format = GDK_MEMORY_R16G16B16,
.is_yuv = TRUE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_P016,
.memory_format = GDK_MEMORY_R16G16B16,
.is_yuv = TRUE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_G16_B16R16_2PLANE_422_UNORM,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_P030,
.memory_format = GDK_MEMORY_R16G16B16,
.is_yuv = TRUE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_UNDEFINED,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
/* 3-plane YUV */
{
.fourcc = DRM_FORMAT_Q410,
.memory_format = GDK_MEMORY_R16G16B16,
.is_yuv = TRUE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_Q401,
.memory_format = GDK_MEMORY_R16G16B16,
.is_yuv = TRUE,
.download = NULL,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM,
.swizzle = VULKAN_SWIZZLE (B, G, R, A),
},
#endif
},
{
.fourcc = DRM_FORMAT_YUV410,
.memory_format = GDK_MEMORY_R8G8B8,
.is_yuv = TRUE,
.download = download_yuv_3,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_UNDEFINED,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_YVU410,
.memory_format = GDK_MEMORY_R8G8B8,
.is_yuv = TRUE,
.download = download_yuv_3,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_UNDEFINED,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_YUV411,
.memory_format = GDK_MEMORY_R8G8B8,
.is_yuv = TRUE,
.download = download_yuv_3,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_UNDEFINED,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_YVU411,
.memory_format = GDK_MEMORY_R8G8B8,
.is_yuv = TRUE,
.download = download_yuv_3,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_UNDEFINED,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_YUV420,
.memory_format = GDK_MEMORY_R8G8B8,
.is_yuv = TRUE,
.download = download_yuv_3,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_YVU420,
.memory_format = GDK_MEMORY_R8G8B8,
.is_yuv = TRUE,
.download = download_yuv_3,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM,
.swizzle = VULKAN_SWIZZLE (B, G, R, A),
},
#endif
},
{
.fourcc = DRM_FORMAT_YUV422,
.memory_format = GDK_MEMORY_R8G8B8,
.is_yuv = TRUE,
.download = download_yuv_3,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_YVU422,
.memory_format = GDK_MEMORY_R8G8B8,
.is_yuv = TRUE,
.download = download_yuv_3,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM,
.swizzle = VULKAN_SWIZZLE (B, G, R, A),
},
#endif
},
{
.fourcc = DRM_FORMAT_YUV444,
.memory_format = GDK_MEMORY_R8G8B8,
.is_yuv = TRUE,
.download = download_yuv_3,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM,
.swizzle = VULKAN_DEFAULT_SWIZZLE,
},
#endif
},
{
.fourcc = DRM_FORMAT_YVU444,
.memory_format = GDK_MEMORY_R8G8B8,
.is_yuv = TRUE,
.download = download_yuv_3,
#ifdef GDK_RENDERING_VULKAN
.vk = {
.format = VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM,
.swizzle = VULKAN_SWIZZLE (B, G, R, A),
},
#endif
},
};
#undef VULKAN_DEFAULT_SWIZZLE
#undef VULKAN_SWIZZLE
static const GdkDrmFormatInfo *
get_drm_format_info (guint32 fourcc)
{
for (int i = 0; i < G_N_ELEMENTS (supported_formats); i++)
{
if (supported_formats[i].fourcc == fourcc)
return &supported_formats[i];
}
return NULL;
}
gboolean
gdk_dmabuf_fourcc_is_yuv (guint32 fourcc,
gboolean *is_yuv)
{
const GdkDrmFormatInfo *info = get_drm_format_info (fourcc);
if (info == NULL)
return FALSE;
*is_yuv = info->is_yuv;
return TRUE;
}
gboolean
gdk_dmabuf_get_memory_format (guint32 fourcc,
gboolean premultiplied,
GdkMemoryFormat *out_format)
{
const GdkDrmFormatInfo *info = get_drm_format_info (fourcc);
if (info == NULL)
return FALSE;
if (premultiplied)
*out_format = gdk_memory_format_get_premultiplied (info->memory_format);
else
*out_format = gdk_memory_format_get_straight (info->memory_format);
return TRUE;
}
#ifdef GDK_RENDERING_VULKAN
gboolean
gdk_dmabuf_vk_get_nth (gsize n,
guint32 *fourcc,
VkFormat *vk_format)
{
if (n >= G_N_ELEMENTS (supported_formats))
return FALSE;
*fourcc = supported_formats[n].fourcc;
*vk_format = supported_formats[n].vk.format;
return TRUE;
}
VkFormat
gdk_dmabuf_get_vk_format (guint32 fourcc,
VkComponentMapping *out_components)
{
const GdkDrmFormatInfo *info = get_drm_format_info (fourcc);
if (info == NULL)
return VK_FORMAT_UNDEFINED;
if (out_components)
*out_components = info->vk.swizzle;
return info->vk.format;
}
#endif
GdkDmabufFormats *
gdk_dmabuf_get_mmap_formats (void)
{
static GdkDmabufFormats *formats = NULL;
if (formats == NULL)
{
GdkDmabufFormatsBuilder *builder;
gsize i;
builder = gdk_dmabuf_formats_builder_new ();
for (i = 0; i < G_N_ELEMENTS (supported_formats); i++)
{
if (!supported_formats[i].download)
continue;
GDK_DEBUG (DMABUF,
"mmap dmabuf format %.4s:%#0" G_GINT64_MODIFIER "x",
(char *) &supported_formats[i].fourcc, (guint64) DRM_FORMAT_MOD_LINEAR);
gdk_dmabuf_formats_builder_add_format (builder,
supported_formats[i].fourcc,
DRM_FORMAT_MOD_LINEAR);
}
formats = gdk_dmabuf_formats_builder_free_to_formats (builder);
}
return formats;
}
static void
gdk_dmabuf_do_download_mmap (GdkTexture *texture,
guchar *data,
gsize stride)
{
const GdkDrmFormatInfo *info;
const GdkDmabuf *dmabuf;
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));
info = get_drm_format_info (dmabuf->fourcc);
g_return_if_fail (info && info->download);
GDK_DISPLAY_DEBUG (gdk_dmabuf_texture_get_display (GDK_DMABUF_TEXTURE (texture)), DMABUF,
"Using mmap for downloading %dx%d dmabuf (format %.4s:%#" G_GINT64_MODIFIER "x)",
gdk_texture_get_width (texture), gdk_texture_get_height (texture),
(char *)&dmabuf->fourcc, dmabuf->modifier);
for (i = 0; i < dmabuf->n_planes; i++)
{
for (j = 0; j < i; j++)
{
if (dmabuf->planes[i].fd == dmabuf->planes[j].fd)
break;
}
if (j < i)
{
src_data[i] = src_data[j];
sizes[i] = sizes[j];
continue;
}
sizes[i] = lseek (dmabuf->planes[i].fd, 0, SEEK_END);
if (sizes[i] == (off_t) -1)
{
g_warning ("Failed to seek dmabuf: %s", g_strerror (errno));
goto out;
}
/* be a good citizen and seek back to the start, as the docs recommend */
lseek (dmabuf->planes[i].fd, 0, SEEK_SET);
if (gdk_dmabuf_ioctl (dmabuf->planes[i].fd, DMA_BUF_IOCTL_SYNC, &(struct dma_buf_sync) { DMA_BUF_SYNC_START|DMA_BUF_SYNC_READ }) < 0)
g_warning ("Failed to sync dmabuf: %s", g_strerror (errno));
src_data[i] = mmap (NULL, sizes[i], PROT_READ, MAP_SHARED, dmabuf->planes[i].fd, dmabuf->planes[i].offset);
if (src_data[i] == NULL)
{
g_warning ("Failed to mmap dmabuf: %s", g_strerror (errno));
goto out;
}
needs_unmap[i] = TRUE;
}
info->download (data,
stride,
gdk_texture_get_format (texture),
gdk_texture_get_width (texture),
gdk_texture_get_height (texture),
dmabuf,
src_data,
sizes);
out:
for (i = 0; i < dmabuf->n_planes; i++)
{
if (!needs_unmap[i])
continue;
munmap ((void *)src_data[i], sizes[i]);
if (gdk_dmabuf_ioctl (dmabuf->planes[i].fd, DMA_BUF_IOCTL_SYNC, &(struct dma_buf_sync) { DMA_BUF_SYNC_END|DMA_BUF_SYNC_READ }) < 0)
g_warning ("Failed to sync dmabuf: %s", g_strerror (errno));
}
}
void
gdk_dmabuf_download_mmap (GdkTexture *texture,
GdkMemoryFormat format,
guchar *data,
gsize stride)
{
GdkMemoryFormat src_format = gdk_texture_get_format (texture);
if (format == src_format)
gdk_dmabuf_do_download_mmap (texture, data, stride);
else
{
unsigned int width, height;
guchar *src_data;
gsize src_stride;
width = gdk_texture_get_width (texture);
height = gdk_texture_get_height (texture);
src_stride = width * gdk_memory_format_bytes_per_pixel (src_format);
src_data = g_new (guchar, src_stride * height);
gdk_dmabuf_do_download_mmap (texture, src_data, src_stride);
gdk_memory_convert (data, stride, format,
src_data, src_stride, src_format,
width, height);
g_free (src_data);
}
}
int
gdk_dmabuf_ioctl (int fd,
unsigned long request,
void *arg)
{
int ret;
do {
ret = ioctl (fd, request, arg);
} while (ret == -1 && (errno == EINTR || errno == EAGAIN));
return ret;
}
#if !defined(DMA_BUF_IOCTL_IMPORT_SYNC_FILE)
struct dma_buf_import_sync_file
{
__u32 flags;
__s32 fd;
};
#define DMA_BUF_IOCTL_IMPORT_SYNC_FILE _IOW(DMA_BUF_BASE, 3, struct dma_buf_import_sync_file)
#endif
gboolean
gdk_dmabuf_import_sync_file (int dmabuf_fd,
guint32 flags,
int sync_file_fd)
{
struct dma_buf_import_sync_file data = {
.flags = flags,
.fd = sync_file_fd,
};
if (gdk_dmabuf_ioctl (dmabuf_fd, DMA_BUF_IOCTL_IMPORT_SYNC_FILE, &data) != 0)
{
GDK_DEBUG (DMABUF, "Importing dmabuf sync failed: %s", g_strerror (errno));
return FALSE;
}
return TRUE;
}
#if !defined(DMA_BUF_IOCTL_EXPORT_SYNC_FILE)
struct dma_buf_export_sync_file
{
__u32 flags;
__s32 fd;
};
#define DMA_BUF_IOCTL_EXPORT_SYNC_FILE _IOWR(DMA_BUF_BASE, 2, struct dma_buf_export_sync_file)
#endif
int
gdk_dmabuf_export_sync_file (int dmabuf_fd,
guint32 flags)
{
struct dma_buf_export_sync_file data = {
.flags = flags,
.fd = -1,
};
if (gdk_dmabuf_ioctl (dmabuf_fd, DMA_BUF_IOCTL_EXPORT_SYNC_FILE, &data) != 0)
{
GDK_DEBUG (DMABUF, "Exporting dmabuf sync failed: %s", g_strerror (errno));
return -1;
}
return data.fd;
}
/*
* Tries to sanitize the dmabuf to conform to the values expected
* by Vulkan/EGL which should also be the values expected by
* Wayland compositors
*
* We put these sanitized values into the GdkDmabufTexture, by
* sanitizing the input from GdkDmabufTextureBuilder, which are
* controlled by the callers.
*
* Things we do here:
*
* 1. Disallow any dmabuf format that we do not know.
*
* 2. Ignore non-linear modifiers.
*
* 3. Try and fix various inconsistencies between V4L and Mesa
* for linear modifiers, like the e.g. single-plane NV12.
*
* *** WARNING ***
*
* This function is not absolutely perfect, you do not have a
* perfect dmabuf afterwards.
*
* In particular, it doesn't check sizes.
*
* *** WARNING ***
*/
gboolean
gdk_dmabuf_sanitize (GdkDmabuf *dest,
gsize width,
gsize height,
const GdkDmabuf *src,
GError **error)
{
const GdkDrmFormatInfo *info;
if (src->n_planes > GDK_DMABUF_MAX_PLANES)
{
g_set_error (error,
GDK_DMABUF_ERROR, GDK_DMABUF_ERROR_UNSUPPORTED_FORMAT,
"GTK only support dmabufs with %u planes, not %u",
GDK_DMABUF_MAX_PLANES, src->n_planes);
return FALSE;
}
info = get_drm_format_info (src->fourcc);
if (info == NULL)
{
g_set_error (error,
GDK_DMABUF_ERROR, GDK_DMABUF_ERROR_UNSUPPORTED_FORMAT,
"Unsupported dmabuf format %.4s",
(char *) &src->fourcc);
return FALSE;
}
*dest = *src;
if (src->modifier)
return TRUE;
switch (dest->fourcc)
{
case DRM_FORMAT_NV12:
case DRM_FORMAT_NV21:
case DRM_FORMAT_NV16:
case DRM_FORMAT_NV61:
if (dest->n_planes == 1)
{
dest->n_planes = 2;
dest->planes[1].fd = dest->planes[0].fd;
dest->planes[1].stride = dest->planes[0].stride;
dest->planes[1].offset = dest->planes[0].offset + dest->planes[0].stride * height;
}
break;
case DRM_FORMAT_NV24:
case DRM_FORMAT_NV42:
if (dest->n_planes == 1)
{
dest->n_planes = 2;
dest->planes[1].fd = dest->planes[0].fd;
dest->planes[1].stride = dest->planes[0].stride * 2;
dest->planes[1].offset = dest->planes[0].offset + dest->planes[0].stride * height;
}
break;
case DRM_FORMAT_YUV410:
case DRM_FORMAT_YVU410:
if (dest->n_planes == 1)
{
dest->n_planes = 3;
dest->planes[1].fd = dest->planes[0].fd;
dest->planes[1].stride = (dest->planes[0].stride + 3) / 4;
dest->planes[1].offset = dest->planes[0].offset + dest->planes[0].stride * height;
dest->planes[2].fd = dest->planes[1].fd;
dest->planes[2].stride = dest->planes[1].stride;
dest->planes[2].offset = dest->planes[1].offset + dest->planes[1].stride * ((height + 3) / 4);
}
break;
case DRM_FORMAT_YUV411:
case DRM_FORMAT_YVU411:
if (dest->n_planes == 1)
{
dest->n_planes = 3;
dest->planes[1].fd = dest->planes[0].fd;
dest->planes[1].stride = (dest->planes[0].stride + 3) / 4;
dest->planes[1].offset = dest->planes[0].offset + dest->planes[0].stride * height;
dest->planes[2].fd = dest->planes[1].fd;
dest->planes[2].stride = dest->planes[1].stride;
dest->planes[2].offset = dest->planes[1].offset + dest->planes[1].stride * height;
}
break;
case DRM_FORMAT_YUV420:
case DRM_FORMAT_YVU420:
if (dest->n_planes == 1)
{
dest->n_planes = 3;
dest->planes[1].fd = dest->planes[0].fd;
dest->planes[1].stride = (dest->planes[0].stride + 1) / 2;
dest->planes[1].offset = dest->planes[0].offset + dest->planes[0].stride * height;
dest->planes[2].fd = dest->planes[1].fd;
dest->planes[2].stride = dest->planes[1].stride;
dest->planes[2].offset = dest->planes[1].offset + dest->planes[1].stride * ((height + 1) / 2);
}
break;
case DRM_FORMAT_YUV422:
case DRM_FORMAT_YVU422:
if (dest->n_planes == 1)
{
dest->n_planes = 3;
dest->planes[1].fd = dest->planes[0].fd;
dest->planes[1].stride = (dest->planes[0].stride + 1) / 2;
dest->planes[1].offset = dest->planes[0].offset + dest->planes[0].stride * height;
dest->planes[2].fd = dest->planes[1].fd;
dest->planes[2].stride = dest->planes[1].stride;
dest->planes[2].offset = dest->planes[1].offset + dest->planes[1].stride * height;
}
break;
case DRM_FORMAT_YUV444:
case DRM_FORMAT_YVU444:
if (dest->n_planes == 1)
{
dest->n_planes = 3;
dest->planes[1].fd = dest->planes[0].fd;
dest->planes[1].stride = dest->planes[0].stride;
dest->planes[1].offset = dest->planes[0].offset + dest->planes[0].stride * height;
dest->planes[2].fd = dest->planes[1].fd;
dest->planes[2].stride = dest->planes[1].stride;
dest->planes[2].offset = dest->planes[1].offset + dest->planes[1].stride * height;
}
break;
default:
break;
}
return TRUE;
}
/*
* gdk_dmabuf_is_disjoint:
* @dmabuf: a sanitized GdkDmabuf
*
* A dmabuf is considered disjoint if it uses more than
* 1 inode.
* Multiple file descriptors may exist when the creator
* of the dmabuf just dup()ed once for every plane...
*
* Returns: %TRUE if the dmabuf is disjoint
**/
gboolean
gdk_dmabuf_is_disjoint (const GdkDmabuf *dmabuf)
{
struct stat first_stat;
unsigned i;
/* First, do a fast check */
for (i = 1; i < dmabuf->n_planes; i++)
{
if (dmabuf->planes[0].fd != dmabuf->planes[i].fd)
break;
}
if (i == dmabuf->n_planes)
return FALSE;
/* We have different fds, do the fancy check instead */
if (fstat (dmabuf->planes[0].fd, &first_stat) != 0)
return TRUE;
for (i = 1; i < dmabuf->n_planes; i++)
{
struct stat plane_stat;
if (fstat (dmabuf->planes[0].fd, &plane_stat) != 0)
return TRUE;
if (first_stat.st_ino != plane_stat.st_ino)
return TRUE;
}
return FALSE;
}
#endif /* HAVE_DMABUF */