Compare commits

...

15 Commits

Author SHA1 Message Date
Matthias Clasen
42fcaa95c9 tests: Add --dmabuf to compare-render
This walks the node tree and turns every texture it finds into
a dmabuf texture.
2024-08-02 13:45:00 -04:00
Matthias Clasen
5ab0aa23e8 Fix P010 download
P010 has zeros in the 6 low bits. So what we want to do here is
to shift the top bits down and add them. This is necessary to
make the 'white' value in P010 (which is 1111111111000000) match
the highest value of 0xffff.
2024-08-02 13:45:00 -04:00
Matthias Clasen
a6e898417a gpu: When importing dmabufs, adjust colorstate
We need to account for the yuv->rgb conversion that may happen
during import. Use the new color state adjustment helper for this.
2024-08-02 13:45:00 -04:00
Matthias Clasen
6a2d662bb9 gpu: Add a helper to adjust color states
Add a function that takes an image and a colorstate, and adjusts
the colorstate according to the image flags. Note: this function
returns a reference.
2024-08-02 13:45:00 -04:00
Matthias Clasen
0ef7bb990b gsk: Add image flags for yuv
We want to separate the yuv->rgb conversion from the texture
upload, and if we do so we need to keep a record of whether it
happened or not.

Also add a mask that collects all the yuv-related flags for
convenient checking.
2024-08-02 13:45:00 -04:00
Matthias Clasen
270b2afcd4 egl: Use correct yuv details for importing
Make the dmabuf import api take color space and range hints as
ints, and update all callers to pass them.

The callers use the new dmabuf egl yuv hints helper api to get
this information from the dmabuf + colorstate. Note that the old
gl renderer is not handling color states carefully and may not
get dmabuf import right wrt to color states.
2024-08-02 13:45:00 -04:00
Matthias Clasen
5d7bd3db87 Add a helper for egl yuv hints 2024-08-02 13:45:00 -04:00
Matthias Clasen
ea564c4eea gst: Set matrix coefficients
This is needed to use our color conversion machinery successfully.

We need some heuristics to determine what coefficients and range
to use when gstreamer gives us an 'unspecified' value. For that,
we look at the fourcc.
2024-08-02 13:45:00 -04:00
Matthias Clasen
bc82f31606 jpeg: Save YCrCb data without conversion
If the texture we are saving is in the right colorstate, just use
the data without converting it to srgb first, only for libjpeg to
convert it back.
2024-08-02 13:45:00 -04:00
Matthias Clasen
b5e5389846 jpeg: Load YCbCr data without conversion
We can represent this data with a colorstate now, and feed it into
our color conversion machinery, instead of relying on libjpeg to
do the yuv->rgb conversion.
2024-08-02 13:45:00 -04:00
Matthias Clasen
490779c007 dmabuf: Drop handrolled yuv conversions
Make the download function just unpack the dmabuf format, and
leave the color state conversion to the conversion call that
we do afterwards. This relies on dmabuf textures having the
correct color state set.
2024-08-02 13:45:00 -04:00
Matthias Clasen
d4713a3b26 dmabuf: Set a proper color state for yuv
When we have to guess the color state because none was explicitly
set, take yuv-ness of the dmabuf fourcc into account.
2024-08-02 13:45:00 -04:00
Matthias Clasen
8d6693fffb colorstate: Add yuv support
Add support for some of the yuv-related cicp tuples.

Concretely, this adds bt601, bt709 and bt2020, both in their
narrow and full-range variants.
2024-08-02 13:45:00 -04:00
Matthias Clasen
3b89704da3 gsk: Make gsk_gpu_cache_lookup_tile return a ref
Make this function return a reference to the cached color state.
This will integrate better in the caller where we may have to
create a new color state, and thus need a reference. And since
the function returns a reference to the image as well, it seems
more consistent to return a reference to the color state too.
2024-08-02 13:45:00 -04:00
Matthias Clasen
7d3efe0a11 gsk: Change refcounting of color states
gsk_gpu_lookup_texture may need to return a newly constructed
color state in the future, so make it return a reference, and
update all callers.
2024-08-02 13:45:00 -04:00
33 changed files with 1466 additions and 203 deletions

View File

@@ -209,7 +209,10 @@ gdk_cicp_params_class_init (GdkCicpParamsClass *klass)
* Supported values:
*
* - 0: RGB
* - 1: BT.709
* - 2: unspecified
* - 5,6: BT.601
* - 9: BT.2020
*
* Since: 4.16
*/

View File

@@ -222,3 +222,39 @@ static const float srgb_to_rec2020[9] = {
0.069108, 0.919519, 0.011360,
0.016394, 0.088011, 0.895380,
};
static const float rgb_to_bt601[9] = {
0.299000, 0.587000, 0.114000,
-0.168736, -0.331264, 0.500000,
0.500000, -0.418688, -0.081312,
};
static const float bt601_to_rgb[9] = {
1.000000, 0.000000, 1.402000,
1.000000, -0.344136, -0.714136,
1.000000, 1.772000, 0.000000,
};
static const float rgb_to_bt709[9] = {
0.212600, 0.715200, 0.072200,
-0.114572, -0.385428, 0.500000,
0.500000, -0.454153, -0.045847,
};
static const float bt709_to_rgb[9] = {
1.000000, 0.000000, 1.574800,
1.000000, -0.187324, -0.468124,
1.000000, 1.855600, -0.000000,
};
static const float rgb_to_bt2020[9] = {
0.262700, 0.678000, 0.059300,
-0.139630, -0.360370, 0.500000,
0.500000, -0.459786, -0.040214,
};
static const float bt2020_to_rgb[9] = {
1.000000, -0.000000, 1.474600,
1.000000, -0.164553, -0.571353,
1.000000, 1.881400, -0.000000,
};

View File

@@ -18,6 +18,7 @@
#include "config.h"
#define GDK_COLOR_STATE_IMPL
#include "gdkcolorstateprivate.h"
#include <math.h>
@@ -411,7 +412,7 @@ GdkDefaultColorState gdk_default_color_states[] = {
},
};
/* }}} */
/* }}} */
/* {{{ Cicp implementation */
typedef struct _GdkCicpColorState GdkCicpColorState;
@@ -431,25 +432,128 @@ struct _GdkCicpColorState
float *from_srgb;
float *from_rec2020;
const float *from_yuv;
const float *to_yuv;
GdkCicp cicp;
};
/* {{{ Conversion functions */
#define cicp ((GdkCicpColorState *)self)
#define TRANSFORM_FROM_CICP(name, matrix, oetf) \
static void \
name (GdkColorState *color_state, \
float (*values)[4], \
gsize n_values) \
{ \
GdkCicpColorState *self = (GdkCicpColorState *) color_state; \
\
for (gsize i = 0; i < n_values; i++) \
{ \
if (self->cicp.range == GDK_CICP_RANGE_NARROW) \
{ \
values[i][0] = CLAMP ((values[i][0] - 16.0/255.0) * 255.0 / 219.0, -10, 10); \
values[i][1] = CLAMP ((values[i][1] - 16.0/255.0) * 255.0 / 224.0, -10, 10); \
values[i][2] = CLAMP ((values[i][2] - 16.0/255.0) * 255.0 / 224.0, -10, 10); \
} \
if (self->from_yuv) \
{ \
float res[3]; \
values[i][1] -= 0.5; \
values[i][2] -= 0.5; \
res[0] = self->from_yuv[0] * values[i][0] + self->from_yuv[1] * values[i][1] + self->from_yuv[2] * values[i][2]; \
res[1] = self->from_yuv[3] * values[i][0] + self->from_yuv[4] * values[i][1] + self->from_yuv[5] * values[i][2]; \
res[2] = self->from_yuv[6] * values[i][0] + self->from_yuv[7] * values[i][1] + self->from_yuv[8] * values[i][2]; \
values[i][0] = res[0]; \
values[i][1] = res[1]; \
values[i][2] = res[2]; \
} \
if (self->eotf != NONE) \
{ \
values[i][0] = self->eotf (values[i][0]); \
values[i][1] = self->eotf (values[i][1]); \
values[i][2] = self->eotf (values[i][2]); \
} \
if (self->matrix != IDENTITY) \
{ \
float res[3]; \
res[0] = self->matrix[0] * values[i][0] + self->matrix[1] * values[i][1] + self->matrix[2] * values[i][2]; \
res[1] = self->matrix[3] * values[i][0] + self->matrix[4] * values[i][1] + self->matrix[5] * values[i][2]; \
res[2] = self->matrix[6] * values[i][0] + self->matrix[7] * values[i][1] + self->matrix[8] * values[i][2]; \
values[i][0] = res[0]; \
values[i][1] = res[1]; \
values[i][2] = res[2]; \
} \
if (oetf != NONE) \
{ \
values[i][0] = oetf (values[i][0]); \
values[i][1] = oetf (values[i][1]); \
values[i][2] = oetf (values[i][2]); \
} \
} \
}
TRANSFORM(gdk_cicp_to_srgb, cicp->eotf, cicp->to_srgb, srgb_oetf)
TRANSFORM(gdk_cicp_to_srgb_linear, cicp->eotf, cicp->to_srgb, NONE)
TRANSFORM(gdk_cicp_to_rec2100_pq, cicp->eotf, cicp->to_rec2020, pq_oetf)
TRANSFORM(gdk_cicp_to_rec2100_linear, cicp->eotf, cicp->to_rec2020, NONE)
TRANSFORM(gdk_cicp_from_srgb, srgb_eotf, cicp->from_srgb, cicp->oetf)
TRANSFORM(gdk_cicp_from_srgb_linear, NONE, cicp->from_srgb, cicp->oetf)
TRANSFORM(gdk_cicp_from_rec2100_pq, pq_eotf, cicp->from_rec2020, cicp->oetf)
TRANSFORM(gdk_cicp_from_rec2100_linear, NONE, cicp->from_rec2020, cicp->oetf)
#define TRANSFORM_TO_CICP(name, eotf, matrix) \
static void \
name (GdkColorState *color_state, \
float (*values)[4], \
gsize n_values) \
{ \
GdkCicpColorState *self = (GdkCicpColorState *) color_state; \
\
for (gsize i = 0; i < n_values; i++) \
{ \
if (eotf != NONE) \
{ \
values[i][0] = eotf (values[i][0]); \
values[i][1] = eotf (values[i][1]); \
values[i][2] = eotf (values[i][2]); \
} \
if (self->matrix != IDENTITY) \
{ \
float res[3]; \
res[0] = self->matrix[0] * values[i][0] + self->matrix[1] * values[i][1] + self->matrix[2] * values[i][2]; \
res[1] = self->matrix[3] * values[i][0] + self->matrix[4] * values[i][1] + self->matrix[5] * values[i][2]; \
res[2] = self->matrix[6] * values[i][0] + self->matrix[7] * values[i][1] + self->matrix[8] * values[i][2]; \
values[i][0] = res[0]; \
values[i][1] = res[1]; \
values[i][2] = res[2]; \
} \
if (self->oetf != NONE) \
{ \
values[i][0] = self->oetf (values[i][0]); \
values[i][1] = self->oetf (values[i][1]); \
values[i][2] = self->oetf (values[i][2]); \
} \
if (self->to_yuv) \
{ \
float res[3]; \
res[0] = self->to_yuv[0] * values[i][0] + self->to_yuv[1] * values[i][1] + self->to_yuv[2] * values[i][2]; \
res[1] = self->to_yuv[3] * values[i][0] + self->to_yuv[4] * values[i][1] + self->to_yuv[5] * values[i][2]; \
res[2] = self->to_yuv[6] * values[i][0] + self->to_yuv[7] * values[i][1] + self->to_yuv[8] * values[i][2]; \
values[i][0] = res[0]; \
values[i][1] = res[1] + 0.5; \
values[i][2] = res[2] + 0.5; \
} \
if (self->cicp.range == GDK_CICP_RANGE_NARROW) \
{ \
values[i][0] = values[i][0] * 219.0 / 255.0 + 16.0 / 255.0; \
values[i][1] = values[i][1] * 224.0 / 255.0 + 16.0 / 255.0; \
values[i][2] = values[i][2] * 224.0 / 255.0 + 16.0 / 255.0; \
} \
} \
}
#undef cicp
TRANSFORM_FROM_CICP(gdk_cicp_to_srgb, to_srgb, srgb_oetf)
TRANSFORM_FROM_CICP(gdk_cicp_to_srgb_linear, to_srgb, NONE)
TRANSFORM_FROM_CICP(gdk_cicp_to_rec2100_pq, to_rec2020, pq_oetf)
TRANSFORM_FROM_CICP(gdk_cicp_to_rec2100_linear, to_rec2020, NONE)
TRANSFORM_TO_CICP(gdk_cicp_from_srgb, srgb_eotf, from_srgb)
TRANSFORM_TO_CICP(gdk_cicp_from_srgb_linear, NONE, from_srgb)
TRANSFORM_TO_CICP(gdk_cicp_from_rec2100_pq, pq_eotf, from_rec2020)
TRANSFORM_TO_CICP(gdk_cicp_from_rec2100_linear, NONE, from_rec2020)
/* }}} */
/* }}} */
/* {{{ Vfuncs */
@@ -555,7 +659,7 @@ gdk_cicp_color_state_get_cicp (GdkColorState *color_state)
return &self->cicp;
}
/* }}} */
/* }}} */
static const
GdkColorStateClass GDK_CICP_COLOR_STATE_CLASS = {
@@ -568,6 +672,46 @@ GdkColorStateClass GDK_CICP_COLOR_STATE_CLASS = {
.get_cicp = gdk_cicp_color_state_get_cicp,
};
GdkCicpColorState gdk_color_state_bt601_narrow = {
.parent = {
.klass = &GDK_CICP_COLOR_STATE_CLASS,
.ref_count = 1,
.depth = GDK_MEMORY_FLOAT16,
.rendering_color_state = GDK_COLOR_STATE_REC2100_LINEAR,
},
.name = "cicp-1/13/6/0",
.no_srgb = NULL,
.cicp = { 1, 13, 6, 0 },
.eotf = srgb_eotf,
.oetf = srgb_oetf,
.to_yuv = rgb_to_bt601,
.from_yuv = bt601_to_rgb,
.to_srgb = IDENTITY,
.to_rec2020 = (float *) srgb_to_rec2020,
.from_srgb = IDENTITY,
.from_rec2020 = (float *) rec2020_to_srgb,
};
GdkCicpColorState gdk_color_state_bt601_full = {
.parent = {
.klass = &GDK_CICP_COLOR_STATE_CLASS,
.ref_count = 1,
.depth = GDK_MEMORY_FLOAT16,
.rendering_color_state = GDK_COLOR_STATE_REC2100_LINEAR,
},
.name = "cicp-1/13/6/1",
.no_srgb = NULL,
.cicp = { 1, 13, 6, 1 },
.eotf = srgb_eotf,
.oetf = srgb_oetf,
.to_yuv = rgb_to_bt601,
.from_yuv = bt601_to_rgb,
.to_srgb = IDENTITY,
.to_rec2020 = (float *) srgb_to_rec2020,
.from_srgb = IDENTITY,
.from_rec2020 = (float *) rec2020_to_srgb,
};
static inline float *
multiply (float res[9],
const float m1[9],
@@ -592,14 +736,8 @@ gdk_color_state_new_for_cicp (const GdkCicp *cicp,
GdkTransferFunc oetf;
gconstpointer to_xyz;
gconstpointer from_xyz;
if (cicp->range == GDK_CICP_RANGE_NARROW || cicp->matrix_coefficients != 0)
{
g_set_error (error,
G_IO_ERROR, G_IO_ERROR_FAILED,
_("cicp: Narrow range or YUV not supported"));
return NULL;
}
gconstpointer to_yuv = NULL;
gconstpointer from_yuv = NULL;
if (cicp->color_primaries == 2 ||
cicp->transfer_function == 2 ||
@@ -613,10 +751,16 @@ gdk_color_state_new_for_cicp (const GdkCicp *cicp,
for (guint i = 0; i < GDK_COLOR_STATE_N_IDS; i++)
{
if (gdk_cicp_equivalent (cicp, &gdk_default_color_states[i].cicp))
if (gdk_cicp_equal (cicp, &gdk_default_color_states[i].cicp))
return (GdkColorState *) &gdk_default_color_states[i];
}
if (gdk_cicp_equal (cicp, &gdk_color_state_bt601_narrow.cicp))
return gdk_color_state_ref ((GdkColorState *) &gdk_color_state_bt601_narrow);
if (gdk_cicp_equal (cicp, &gdk_color_state_bt601_full.cicp))
return gdk_color_state_ref ((GdkColorState *) &gdk_color_state_bt601_full);
switch (cicp->transfer_function)
{
case 1:
@@ -669,6 +813,7 @@ gdk_color_state_new_for_cicp (const GdkCicp *cicp,
from_xyz = xyz_to_pal;
break;
case 6:
case 7:
to_xyz = ntsc_to_xyz;
from_xyz = xyz_to_ntsc;
break;
@@ -692,6 +837,34 @@ gdk_color_state_new_for_cicp (const GdkCicp *cicp,
return NULL;
}
switch (cicp->matrix_coefficients)
{
case 0:
to_yuv = IDENTITY;
from_yuv = IDENTITY;
break;
case 1:
to_yuv = rgb_to_bt709;
from_yuv = bt709_to_rgb;
break;
case 5:
case 6:
to_yuv = rgb_to_bt601;
from_yuv = bt601_to_rgb;
break;
case 9:
to_yuv = rgb_to_bt2020;
from_yuv = bt2020_to_rgb;
break;
default:
g_set_error (error,
G_IO_ERROR, G_IO_ERROR_FAILED,
_("cicp: Matrix coefficients %u, %s not supported"),
cicp->matrix_coefficients,
cicp->range == GDK_CICP_RANGE_NARROW ? "narrow" : "full");
return NULL;
}
self = g_new0 (GdkCicpColorState, 1);
self->parent.klass = &GDK_CICP_COLOR_STATE_CLASS;
@@ -704,6 +877,9 @@ gdk_color_state_new_for_cicp (const GdkCicp *cicp,
memcpy (&self->cicp, cicp, sizeof (GdkCicp));
self->to_yuv = to_yuv;
self->from_yuv = from_yuv;
self->eotf = eotf;
self->oetf = oetf;

View File

@@ -185,3 +185,11 @@ gdk_color_state_get_cicp (GdkColorState *self)
GdkColorState * gdk_color_state_new_for_cicp (const GdkCicp *cicp,
GError **error);
#ifndef GDK_COLOR_STATE_IMPL
extern GdkColorState gdk_color_state_bt601_narrow;
extern GdkColorState gdk_color_state_bt601_full;
#endif
#define GDK_COLOR_STATE_YUV ((GdkColorState *) &gdk_color_state_bt601_narrow)
#define GDK_COLOR_STATE_JPEG ((GdkColorState *) &gdk_color_state_bt601_full)

View File

@@ -24,6 +24,7 @@
#include "gdkdmabuffourccprivate.h"
#include "gdkdmabuftextureprivate.h"
#include "gdkmemoryformatprivate.h"
#include "gdkcolorstate.h"
#ifdef HAVE_DMABUF
#include <sys/mman.h>
@@ -133,49 +134,6 @@ download_memcpy_3_1 (guchar *dst_data,
}
}
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,
@@ -226,14 +184,21 @@ download_nv12 (guchar *dst_data,
{
for (x = 0; x < width; x += X_SUB)
{
int r, g, b;
int u_, v_;
gsize xs, ys;
get_uv_values (&itu601_narrow, uv_data[x / X_SUB * 2 + U], uv_data[x / X_SUB * 2 + V], &r, &g, &b);
u_ = uv_data[x / X_SUB * 2 + U];
v_ = uv_data[x / X_SUB * 2 + V];
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);
{
guint8 *rgb = &dst_data[3 * (x + xs) + dst_stride * ys];
rgb[0] = y_data[x + xs + y_stride * ys];
rgb[1] = u_;
rgb[2] = v_;
}
}
dst_data += Y_SUB * dst_stride;
y_data += Y_SUB * y_stride;
@@ -241,35 +206,6 @@ download_nv12 (guchar *dst_data,
}
}
static inline void
get_uv_values16 (const YUVCoefficients *coeffs,
guint16 u,
guint16 v,
gint64 *out_r,
gint64 *out_g,
gint64 *out_b)
{
gint64 u2 = (gint64) u - 32767;
gint64 v2 = (gint64) v - 32767;
*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_values16 (guint16 rgb[3],
guint16 y,
gint64 r,
gint64 g,
gint64 b)
{
gint64 y2 = (gint64) y * 65536;
rgb[0] = CLAMP ((y2 + r) >> 16, 0, 65535);
rgb[1] = CLAMP ((y2 + g) >> 16, 0, 65535);
rgb[2] = CLAMP ((y2 + b) >> 16, 0, 65535);
}
static void
download_p010 (guchar *dst,
gsize dst_stride,
@@ -284,7 +220,7 @@ download_p010 (guchar *dst,
guint16 *dst_data;
gsize x, y, y_stride, uv_stride;
gsize U, V, X_SUB, Y_SUB;
guint16 SIZE, MASK;
guint16 SIZE;
switch (dmabuf->fourcc)
{
@@ -304,7 +240,6 @@ download_p010 (guchar *dst,
g_assert_not_reached ();
return;
}
MASK = 0xFFFF << (16 - SIZE);
y_stride = dmabuf->planes[0].stride / 2;
y_data = (const guint16 *) (src_data[0] + dmabuf->planes[0].offset);
@@ -319,22 +254,24 @@ download_p010 (guchar *dst,
{
for (x = 0; x < width; x += X_SUB)
{
gint64 r, g, b;
gsize xs, ys;
guint16 u, v;
guint16 u_, v_;
u = uv_data[x / X_SUB * 2 + U];
u = (u & MASK) | (u >> SIZE);
v = uv_data[x / X_SUB * 2 + V];
v = (v & MASK) | (v >> SIZE);
get_uv_values16 (&itu601_narrow, u, v, &r, &g, &b);
u_ = uv_data[x / X_SUB * 2 + U];
u_ = u_ | (u_ >> SIZE);
v_ = uv_data[x / X_SUB * 2 + V];
v_ = v_ | (v_ >> SIZE);
for (ys = 0; ys < Y_SUB && y + ys < height; ys++)
for (xs = 0; xs < X_SUB && x + xs < width; xs++)
{
guint16 *rgb = &dst_data[3 * (x + xs) + dst_stride * ys];
guint16 y_ = y_data[x + xs + y_stride * ys];
y_ = (y_ & MASK) | (y_ >> SIZE);
set_rgb_values16 (&dst_data[3 * (x + xs) + dst_stride * ys], y_, r, g, b);
y_ = y_ | (y_ >> SIZE);
rgb[0] = y_;
rgb[1] = u_;
rgb[2] = v_;
}
}
dst_data += Y_SUB * dst_stride;
@@ -408,14 +345,21 @@ download_yuv_3 (guchar *dst_data,
{
for (x = 0; x < width; x += X_SUB)
{
int r, g, b;
int u_, v_;
gsize xs, ys;
get_uv_values (&itu601_narrow, u_data[x / X_SUB], v_data[x / X_SUB], &r, &g, &b);
u_ = u_data[x / X_SUB];
v_ = v_data[x / X_SUB];
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);
{
guint8 *rgb = &dst_data[3 * (x + xs) + dst_stride * ys];
rgb[0] = y_data[x + xs + y_stride * ys];
rgb[1] = u_;
rgb[2] = v_;
}
}
dst_data += Y_SUB * dst_stride;
y_data += Y_SUB * y_stride;
@@ -465,12 +409,23 @@ download_yuyv (guchar *dst_data,
{
for (x = 0; x < width; x += 2)
{
int r, g, b;
guint8 *rgb;
int u_, v_;
get_uv_values (&itu601_narrow, 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);
u_ = src_data[2 * x + U];
v_ = src_data[2 * x + V];
rgb = &dst_data[3 * x];
rgb[0] = src_data[2 * x + Y1];
rgb[1] = u_;
rgb[2] = v_;
if (x + 1 < width)
set_rgb_values (&dst_data[3 * (x + 1)], src_data[2 * x + Y2], r, g, b);
{
rgb = &dst_data[3 * (x + 1)];
rgb[0] = src_data[2 * x + Y2];
rgb[1] = u_;
rgb[2] = v_;
}
}
dst_data += dst_stride;
src_data += src_stride;
@@ -2139,14 +2094,14 @@ gdk_dmabuf_do_download_mmap (GdkTexture *texture,
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);
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++)

View File

@@ -209,12 +209,15 @@ gdk_dmabuf_egl_create_image (GdkDisplay *display,
int width,
int height,
const GdkDmabuf *dmabuf,
int color_space_hint,
int range_hint,
int target)
{
EGLDisplay egl_display = gdk_display_get_egl_display (display);
EGLint attribs[64];
int i;
EGLImage image;
gboolean is_yuv;
g_return_val_if_fail (width > 0, 0);
g_return_val_if_fail (height > 0, 0);
@@ -228,6 +231,25 @@ gdk_dmabuf_egl_create_image (GdkDisplay *display,
return EGL_NO_IMAGE;
}
if (gdk_dmabuf_fourcc_is_yuv (dmabuf->fourcc, &is_yuv) && is_yuv)
{
if (color_space_hint == 0 || range_hint == 0)
{
GDK_DISPLAY_DEBUG (display, DMABUF,
"Can't import yuv dmabuf into GL without color space hints");
return EGL_NO_IMAGE;
}
}
else
{
if (color_space_hint != 0 || range_hint != 0)
{
GDK_DISPLAY_DEBUG (display, DMABUF,
"Can't import non-yuv dmabuf into GL with color space hints");
return EGL_NO_IMAGE;
}
}
GDK_DISPLAY_DEBUG (display, DMABUF,
"Importing dmabuf (format: %.4s:%#" G_GINT64_MODIFIER "x, planes: %u) into GL",
(char *) &dmabuf->fourcc, dmabuf->modifier, dmabuf->n_planes);
@@ -241,10 +263,16 @@ gdk_dmabuf_egl_create_image (GdkDisplay *display,
attribs[i++] = height;
attribs[i++] = EGL_LINUX_DRM_FOURCC_EXT;
attribs[i++] = dmabuf->fourcc;
attribs[i++] = EGL_YUV_COLOR_SPACE_HINT_EXT;
attribs[i++] = EGL_ITU_REC601_EXT;
attribs[i++] = EGL_SAMPLE_RANGE_HINT_EXT;
attribs[i++] = EGL_YUV_NARROW_RANGE_EXT;
if (color_space_hint != 0)
{
attribs[i++] = EGL_YUV_COLOR_SPACE_HINT_EXT;
attribs[i++] = color_space_hint;
}
if (range_hint != 0)
{
attribs[i++] = EGL_SAMPLE_RANGE_HINT_EXT;
attribs[i++] = range_hint;
}
#define ADD_PLANE(plane) \
{ \
@@ -289,4 +317,48 @@ gdk_dmabuf_egl_create_image (GdkDisplay *display,
return image;
}
void
gdk_dmabuf_get_egl_yuv_hints (const GdkDmabuf *dmabuf,
GdkColorState *color_state,
int *color_space_hint,
int *range_hint)
{
gboolean is_yuv;
const GdkCicp *cicp;
cicp = gdk_color_state_get_cicp (color_state);
if (cicp &&
gdk_dmabuf_fourcc_is_yuv (dmabuf->fourcc, &is_yuv) && is_yuv)
{
if (cicp->range == GDK_CICP_RANGE_NARROW)
*range_hint = EGL_YUV_NARROW_RANGE_EXT;
else
*range_hint = EGL_YUV_FULL_RANGE_EXT;
switch (cicp->matrix_coefficients)
{
case 1:
*color_space_hint = EGL_ITU_REC709_EXT;
break;
case 5:
case 6:
*color_space_hint = EGL_ITU_REC601_EXT;
break;
case 9:
*color_space_hint = EGL_ITU_REC2020_EXT;
break;
default:
*color_space_hint = 0;
*range_hint = 0;
break;
}
}
else
{
*color_space_hint = 0;
*range_hint = 0;
}
}
#endif /* HAVE_DMABUF && HAVE_EGL */

View File

@@ -13,6 +13,13 @@ EGLImage gdk_dmabuf_egl_create_image (GdkDisplay
int width,
int height,
const GdkDmabuf *dmabuf,
int color_state_hint,
int range_hint,
int target);
void gdk_dmabuf_get_egl_yuv_hints (const GdkDmabuf *dmabuf,
GdkColorState *color_state,
int *color_space_hint,
int *range_hint);
#endif /* HAVE_DMABUF && HAVE_EGL */

View File

@@ -208,12 +208,9 @@ gdk_dmabuf_texture_new_from_builder (GdkDmabufTextureBuilder *builder,
gboolean is_yuv;
if (gdk_dmabuf_fourcc_is_yuv (dmabuf.fourcc, &is_yuv) && is_yuv)
{
g_warning_once ("FIXME: Implement the proper colorstate for YUV dmabufs");
color_state = gdk_color_state_get_srgb ();
}
color_state = GDK_COLOR_STATE_YUV;
else
color_state = gdk_color_state_get_srgb ();
color_state = GDK_COLOR_STATE_SRGB;
}
self = g_object_new (GDK_TYPE_DMABUF_TEXTURE,

View File

@@ -2179,6 +2179,8 @@ gdk_gl_context_import_dmabuf_for_target (GdkGLContext *self,
int width,
int height,
const GdkDmabuf *dmabuf,
int color_space_hint,
int range_hint,
int target)
{
#if defined(HAVE_EGL) && defined(HAVE_DMABUF)
@@ -2190,6 +2192,8 @@ gdk_gl_context_import_dmabuf_for_target (GdkGLContext *self,
width,
height,
dmabuf,
color_space_hint,
range_hint,
target);
if (image == EGL_NO_IMAGE)
return 0;
@@ -2213,6 +2217,8 @@ gdk_gl_context_import_dmabuf (GdkGLContext *self,
int width,
int height,
const GdkDmabuf *dmabuf,
int color_space_hint,
int range_hint,
gboolean *external)
{
GdkDisplay *display = gdk_gl_context_get_display (self);
@@ -2229,6 +2235,8 @@ gdk_gl_context_import_dmabuf (GdkGLContext *self,
texture_id = gdk_gl_context_import_dmabuf_for_target (self,
width, height,
dmabuf,
color_space_hint,
range_hint,
GL_TEXTURE_2D);
if (texture_id == 0)
{
@@ -2258,6 +2266,8 @@ gdk_gl_context_import_dmabuf (GdkGLContext *self,
texture_id = gdk_gl_context_import_dmabuf_for_target (self,
width, height,
dmabuf,
color_space_hint,
range_hint,
GL_TEXTURE_EXTERNAL_OES);
if (texture_id == 0)
{
@@ -2290,6 +2300,8 @@ gdk_gl_context_import_dmabuf (GdkGLContext *self,
texture_id = gdk_gl_context_import_dmabuf_for_target (self,
width, height,
dmabuf,
color_space_hint,
range_hint,
target);
if (texture_id == 0)

View File

@@ -184,6 +184,8 @@ guint gdk_gl_context_import_dmabuf (GdkGLContext
int width,
int height,
const GdkDmabuf *dmabuf,
int color_space_hint,
int range_hint,
gboolean *external);
gboolean gdk_gl_context_export_dmabuf (GdkGLContext *self,

View File

@@ -149,37 +149,39 @@ gdk_load_jpeg (GBytes *input_bytes,
g_bytes_get_size (input_bytes));
jpeg_read_header (&info, TRUE);
if (info.jpeg_color_space == JCS_GRAYSCALE)
{
color_state = GDK_COLOR_STATE_SRGB;
info.out_color_space = JCS_GRAYSCALE;
format = GDK_MEMORY_G8;
}
else if (info.jpeg_color_space == JCS_YCbCr)
{
color_state = GDK_COLOR_STATE_JPEG;
info.out_color_space = JCS_YCbCr;
format = GDK_MEMORY_R8G8B8;
}
else if (info.jpeg_color_space == JCS_CMYK)
{
color_state = GDK_COLOR_STATE_SRGB;
info.out_color_space = JCS_CMYK;
format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED;
}
else
{
color_state = GDK_COLOR_STATE_SRGB;
info.out_color_space = JCS_RGB;
format = GDK_MEMORY_R8G8B8;
}
jpeg_start_decompress (&info);
width = info.output_width;
height = info.output_height;
stride = gdk_memory_format_bytes_per_pixel (format) * width;
color_state = GDK_COLOR_STATE_SRGB;
switch ((int)info.out_color_space)
{
case JCS_GRAYSCALE:
stride = width;
data = g_try_malloc_n (stride, height);
format = GDK_MEMORY_G8;
break;
case JCS_RGB:
stride = 3 * width;
data = g_try_malloc_n (stride, height);
format = GDK_MEMORY_R8G8B8;
break;
case JCS_CMYK:
stride = 4 * width;
data = g_try_malloc_n (stride, height);
format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED;
break;
default:
g_set_error (error,
GDK_TEXTURE_ERROR, GDK_TEXTURE_ERROR_UNSUPPORTED_CONTENT,
_("Unsupported JPEG colorspace (%d)"), info.out_color_space);
jpeg_destroy_decompress (&info);
return NULL;
}
data = g_try_malloc_n (stride, height);
if (!data)
{
@@ -215,7 +217,6 @@ gdk_load_jpeg (GBytes *input_bytes,
texture = gdk_memory_texture_builder_build (builder);
gdk_color_state_unref (color_state);
g_object_unref (builder);
g_bytes_unref (bytes);
@@ -239,6 +240,7 @@ gdk_save_jpeg (GdkTexture *texture)
gsize texstride;
guchar *row;
int width, height;
GdkColorState *color_state;
width = gdk_texture_get_width (texture);
height = gdk_texture_get_height (texture);
@@ -268,13 +270,24 @@ gdk_save_jpeg (GdkTexture *texture)
jpeg_set_defaults (&info);
jpeg_set_quality (&info, 75, TRUE);
color_state = gdk_texture_get_color_state (texture);
if (gdk_color_state_equal (color_state, GDK_COLOR_STATE_JPEG))
{
info.in_color_space = JCS_YCbCr;
}
else
{
info.in_color_space = JCS_RGB;
color_state = GDK_COLOR_STATE_SRGB;
}
info.mem->max_memory_to_use = 300 * 1024 * 1024;
jpeg_mem_dest (&info, &data, &size);
gdk_texture_downloader_init (&downloader, texture);
gdk_texture_downloader_set_format (&downloader, GDK_MEMORY_R8G8B8);
gdk_texture_downloader_set_color_state (&downloader, GDK_COLOR_STATE_SRGB);
gdk_texture_downloader_set_color_state (&downloader, color_state);
texbytes = gdk_texture_downloader_download_bytes (&downloader, &texstride);
gdk_texture_downloader_finish (&downloader);
texdata = g_bytes_get_data (texbytes, NULL);

View File

@@ -43,6 +43,7 @@
#include <gdk/gdkmemoryformatprivate.h>
#include <gdk/gdkprofilerprivate.h>
#include <gdk/gdktextureprivate.h>
#include <gdk/gdkdmabufeglprivate.h>
#include <gdk/gdkmemoryformatprivate.h>
#include <gdk/gdkdmabuftextureprivate.h>
@@ -811,6 +812,8 @@ gsk_gl_driver_import_dmabuf_texture (GskGLDriver *self,
gboolean external;
GdkMemoryFormat format;
gboolean premultiply;
GdkColorState *color_state;
int color_space, range;
gdk_gl_context_make_current (context);
@@ -828,10 +831,16 @@ gsk_gl_driver_import_dmabuf_texture (GskGLDriver *self,
dmabuf = gdk_dmabuf_texture_get_dmabuf (texture);
format = gdk_texture_get_format (GDK_TEXTURE (texture));
premultiply = gdk_memory_format_alpha (format) == GDK_MEMORY_ALPHA_STRAIGHT;
color_state = gdk_texture_get_color_state (GDK_TEXTURE (texture));
gdk_dmabuf_get_egl_yuv_hints (dmabuf, color_state, &color_space, &range);
texture_id = gdk_gl_context_import_dmabuf (context,
width, height,
dmabuf,
color_space,
range,
&external);
if (texture_id == 0)
return 0;

View File

@@ -10,6 +10,7 @@
#include "gskglimageprivate.h"
#include "gdkdmabuftextureprivate.h"
#include "gdkdmabufeglprivate.h"
#include "gdkglcontextprivate.h"
#include "gdkgltextureprivate.h"
@@ -92,7 +93,7 @@ gsk_gl_frame_upload_texture (GskGpuFrame *frame,
gdk_gl_texture_get_id (gl_texture),
FALSE,
gdk_gl_texture_has_mipmap (gl_texture) ? (GSK_GPU_IMAGE_CAN_MIPMAP | GSK_GPU_IMAGE_MIPMAP) : 0);
/* This is a hack, but it works */
sync = gdk_gl_texture_get_sync (gl_texture);
if (sync)
@@ -105,19 +106,56 @@ gsk_gl_frame_upload_texture (GskGpuFrame *frame,
{
gboolean external;
GLuint tex_id;
int color_space_hint = 0;
int range_hint = 0;
#if defined (HAVE_DMABUF) && defined (HAVE_EGL)
gdk_dmabuf_get_egl_yuv_hints (gdk_dmabuf_texture_get_dmabuf (GDK_DMABUF_TEXTURE (texture)),
gdk_texture_get_color_state (texture),
&color_space_hint,
&range_hint);
#endif
tex_id = gdk_gl_context_import_dmabuf (GDK_GL_CONTEXT (gsk_gpu_frame_get_context (frame)),
gdk_texture_get_width (texture),
gdk_texture_get_height (texture),
gdk_dmabuf_texture_get_dmabuf (GDK_DMABUF_TEXTURE (texture)),
color_space_hint,
range_hint,
&external);
if (tex_id)
{
GskGpuImageFlags flags = 0;
if (external)
flags |= GSK_GPU_IMAGE_EXTERNAL | GSK_GPU_IMAGE_NO_BLIT;
#if defined (HAVE_DMABUF) && defined (HAVE_EGL)
switch (color_space_hint)
{
case EGL_ITU_REC709_EXT:
flags |= GSK_GPU_IMAGE_BT709;
break;
case EGL_ITU_REC601_EXT:
flags |= GSK_GPU_IMAGE_BT601;
break;
case EGL_ITU_REC2020_EXT:
flags |= GSK_GPU_IMAGE_BT2020;
break;
default:
break;
}
if (range_hint == EGL_YUV_NARROW_RANGE_EXT)
flags |= GSK_GPU_IMAGE_NARROW_RANGE;
#endif
return gsk_gl_image_new_for_texture (GSK_GL_DEVICE (gsk_gpu_frame_get_device (frame)),
texture,
tex_id,
TRUE,
(external ? GSK_GPU_IMAGE_EXTERNAL | GSK_GPU_IMAGE_NO_BLIT : 0));
flags);
}
}

View File

@@ -682,7 +682,7 @@ gsk_gpu_cache_lookup_tile (GskGpuCache *self,
gsk_gpu_cached_use (self, (GskGpuCached *) tile);
*out_color_state = tile->color_state;
*out_color_state = gdk_color_state_ref (tile->color_state);
return g_object_ref (tile->image);
}

View File

@@ -36,7 +36,8 @@ gsk_gpu_convert_cicp_op_print_instance (GskGpuShaderOp *shader,
g_string_append_printf (string, "cicp %u/%u/%u/%u",
instance->color_primaries,
instance->transfer_function,
0, 1);
instance->matrix_coefficients,
instance->range);
}
static const GskGpuShaderOpClass GSK_GPU_CONVERT_OP_CLASS = {
@@ -88,6 +89,8 @@ gsk_gpu_convert_from_cicp_op (GskGpuFrame *frame,
instance->opacity = opacity;
instance->color_primaries = cicp->color_primaries;
instance->transfer_function = cicp->transfer_function;
instance->matrix_coefficients = cicp->matrix_coefficients;
instance->range = cicp->range == GDK_CICP_RANGE_NARROW ? 0 : 1;
}
void
@@ -118,4 +121,6 @@ gsk_gpu_convert_to_cicp_op (GskGpuFrame *frame,
instance->opacity = opacity;
instance->color_primaries = cicp->color_primaries;
instance->transfer_function = cicp->transfer_function;
instance->matrix_coefficients = cicp->matrix_coefficients;
instance->range = cicp->range == GDK_CICP_RANGE_NARROW ? 0 : 1;
}

View File

@@ -1,6 +1,7 @@
#include "config.h"
#include "gskgpuimageprivate.h"
#include "gdkcolorstateprivate.h"
typedef struct _GskGpuImagePrivate GskGpuImagePrivate;
@@ -162,3 +163,61 @@ gsk_gpu_image_get_projection_matrix (GskGpuImage *self,
{
GSK_GPU_IMAGE_GET_CLASS (self)->get_projection_matrix (self, out_projection);
}
GdkColorState *
gsk_gpu_image_adjust_color_state (GskGpuImage *self,
GdkColorState *color_state)
{
GskGpuImagePrivate *priv = gsk_gpu_image_get_instance_private (self);
GdkColorState *adjusted;
GdkCicp cicp;
adjusted = gdk_color_state_ref (color_state);
if (priv->flags & GSK_GPU_IMAGE_SRGB)
{
GdkColorState *no_srgb;
no_srgb = gdk_color_state_get_no_srgb_tf (adjusted);
g_assert (no_srgb);
gdk_color_state_unref (adjusted);
adjusted = gdk_color_state_ref (no_srgb);
}
if (!gdk_color_state_get_cicp (adjusted))
return adjusted;
cicp = *gdk_color_state_get_cicp (adjusted);
if (priv->flags & GSK_GPU_IMAGE_NARROW_RANGE)
cicp.range = GDK_CICP_RANGE_FULL;
switch (priv->flags & GSK_GPU_IMAGE_YUV)
{
case GSK_GPU_IMAGE_BT709:
g_assert (cicp.matrix_coefficients == 1);
cicp.matrix_coefficients = 0;
break;
case GSK_GPU_IMAGE_BT601:
g_assert (cicp.matrix_coefficients == 5 ||
cicp.matrix_coefficients == 6);
cicp.matrix_coefficients = 0;
break;
case GSK_GPU_IMAGE_BT2020:
g_assert (cicp.matrix_coefficients == 9);
cicp.matrix_coefficients = 0;
break;
default:
break;
}
if (!gdk_cicp_equal (&cicp, gdk_color_state_get_cicp (adjusted)))
{
gdk_color_state_unref (adjusted);
adjusted = gdk_color_state_new_for_cicp (&cicp, NULL);
g_assert (adjusted);
}
return adjusted;
}

View File

@@ -48,6 +48,9 @@ void gsk_gpu_image_set_flags (GskGpuI
void gsk_gpu_image_get_projection_matrix (GskGpuImage *self,
graphene_matrix_t *out_projection);
GdkColorState * gsk_gpu_image_adjust_color_state (GskGpuImage *self,
GdkColorState *color_state);
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GskGpuImage, g_object_unref)

View File

@@ -1659,7 +1659,6 @@ gsk_gpu_lookup_texture (GskGpuFrame *frame,
GdkColorState **out_image_cs)
{
GskGpuCache *cache;
GdkColorState *image_cs;
GskGpuImage *image;
cache = gsk_gpu_device_get_cache (gsk_gpu_frame_get_device (frame));
@@ -1667,7 +1666,7 @@ gsk_gpu_lookup_texture (GskGpuFrame *frame,
image = gsk_gpu_cache_lookup_texture_image (cache, texture, ccs);
if (image)
{
*out_image_cs = ccs;
*out_image_cs = gdk_color_state_ref (ccs);
return image;
}
@@ -1677,17 +1676,14 @@ gsk_gpu_lookup_texture (GskGpuFrame *frame,
/* Happens ie for oversized textures */
if (image == NULL)
return NULL;
image_cs = gdk_texture_get_color_state (texture);
if (gsk_gpu_image_get_flags (image) & GSK_GPU_IMAGE_SRGB)
{
image_cs = gdk_color_state_get_no_srgb_tf (image_cs);
g_assert (image_cs);
*out_image_cs = NULL;
return NULL;
}
*out_image_cs = image_cs;
*out_image_cs = gsk_gpu_image_adjust_color_state (image,
gdk_texture_get_color_state (texture));
return image;
}
@@ -1721,7 +1717,6 @@ gsk_gpu_node_processor_draw_texture_tiles (GskGpuNodeProcessor *self,
GskGpuCache *cache;
GskGpuDevice *device;
GskGpuImage *tile;
GdkColorState *tile_cs;
GskGpuSampler sampler;
gboolean need_mipmap;
GdkMemoryTexture *memtex;
@@ -1748,6 +1743,8 @@ gsk_gpu_node_processor_draw_texture_tiles (GskGpuNodeProcessor *self,
{
for (x = 0; x < n_width; x++)
{
GdkColorState *tile_cs = NULL;
graphene_rect_t tile_rect = GRAPHENE_RECT_INIT (texture_bounds->origin.x + scaled_tile_width * x,
texture_bounds->origin.y + scaled_tile_height * y,
scaled_tile_width,
@@ -1776,13 +1773,8 @@ gsk_gpu_node_processor_draw_texture_tiles (GskGpuNodeProcessor *self,
goto out;
}
tile_cs = gdk_texture_get_color_state (texture);
if (gsk_gpu_image_get_flags (tile) & GSK_GPU_IMAGE_SRGB)
{
tile_cs = gdk_color_state_get_no_srgb_tf (tile_cs);
g_assert (tile_cs);
}
tile_cs = gsk_gpu_image_adjust_color_state (tile,
gdk_texture_get_color_state (texture));
gsk_gpu_cache_cache_tile (cache, texture, y * n_width + x, tile, tile_cs);
}
@@ -1790,7 +1782,8 @@ gsk_gpu_node_processor_draw_texture_tiles (GskGpuNodeProcessor *self,
(gsk_gpu_image_get_flags (tile) & (GSK_GPU_IMAGE_STRAIGHT_ALPHA | GSK_GPU_IMAGE_CAN_MIPMAP)) != GSK_GPU_IMAGE_CAN_MIPMAP)
{
tile = gsk_gpu_copy_image (self->frame, self->ccs, tile, tile_cs, TRUE);
tile_cs = self->ccs;
gdk_color_state_unref (tile_cs);
tile_cs = gdk_color_state_ref (self->ccs);
gsk_gpu_cache_cache_tile (cache, texture, y * n_width + x, tile, tile_cs);
}
if (need_mipmap && !(gsk_gpu_image_get_flags (tile) & GSK_GPU_IMAGE_MIPMAP))
@@ -1803,6 +1796,7 @@ gsk_gpu_node_processor_draw_texture_tiles (GskGpuNodeProcessor *self,
&tile_rect,
&tile_rect);
gdk_color_state_unref (tile_cs);
g_object_unref (tile);
}
}
@@ -1891,7 +1885,8 @@ gsk_gpu_node_processor_add_texture_node (GskGpuNodeProcessor *self,
!gdk_color_state_equal (image_cs, self->ccs))
{
image = gsk_gpu_copy_image (self->frame, self->ccs, image, image_cs, TRUE);
image_cs = self->ccs;
gdk_color_state_unref (image_cs);
image_cs = gdk_color_state_ref (self->ccs);
gsk_gpu_cache_cache_texture_image (gsk_gpu_device_get_cache (gsk_gpu_frame_get_device (self->frame)),
texture,
image,
@@ -1918,6 +1913,7 @@ gsk_gpu_node_processor_add_texture_node (GskGpuNodeProcessor *self,
&node->bounds);
}
gdk_color_state_unref (image_cs);
g_object_unref (image);
}
@@ -1964,6 +1960,7 @@ gsk_gpu_get_texture_node_as_image (GskGpuFrame *frame,
}
*out_bounds = node->bounds;
gdk_color_state_unref (image_cs);
return image;
}
@@ -2002,6 +1999,7 @@ gsk_gpu_node_processor_add_texture_scale_node (GskGpuNodeProcessor *self,
/* now intersect with actual node bounds */
if (!gsk_rect_intersection (&clip_bounds, &node->bounds, &clip_bounds))
{
gdk_color_state_unref (image_cs);
g_object_unref (image);
return;
}
@@ -2044,7 +2042,8 @@ gsk_gpu_node_processor_add_texture_scale_node (GskGpuNodeProcessor *self,
!gdk_color_state_equal (image_cs, self->ccs))
{
image = gsk_gpu_copy_image (self->frame, self->ccs, image, image_cs, need_mipmap);
image_cs = self->ccs;
gdk_color_state_unref (image_cs);
image_cs = gdk_color_state_ref (self->ccs);
gsk_gpu_cache_cache_texture_image (gsk_gpu_device_get_cache (gsk_gpu_frame_get_device (self->frame)),
texture,
image,
@@ -2064,6 +2063,7 @@ gsk_gpu_node_processor_add_texture_scale_node (GskGpuNodeProcessor *self,
&node->bounds,
});
gdk_color_state_unref (image_cs);
g_object_unref (image);
}

View File

@@ -29,8 +29,14 @@ typedef enum {
GSK_GPU_IMAGE_FILTERABLE = (1 << 6),
GSK_GPU_IMAGE_RENDERABLE = (1 << 7),
GSK_GPU_IMAGE_SRGB = (1 << 8),
GSK_GPU_IMAGE_NARROW_RANGE = (1 << 9),
GSK_GPU_IMAGE_BT601 = (1 << 10),
GSK_GPU_IMAGE_BT709 = (2 << 10),
GSK_GPU_IMAGE_BT2020 = (3 << 10),
} GskGpuImageFlags;
#define GSK_GPU_IMAGE_YUV (GSK_GPU_IMAGE_BT2020)
typedef enum {
GSK_GPU_SAMPLER_DEFAULT,
GSK_GPU_SAMPLER_TRANSPARENT,

View File

@@ -187,6 +187,7 @@ gsk_vulkan_frame_upload_texture (GskGpuFrame *frame,
image = gsk_vulkan_image_new_for_dmabuf (GSK_VULKAN_DEVICE (gsk_gpu_frame_get_device (frame)),
gdk_texture_get_width (texture),
gdk_texture_get_height (texture),
gdk_texture_get_color_state (texture),
&dmabuf,
gdk_memory_format_alpha (gdk_texture_get_format (texture)) == GDK_MEMORY_ALPHA_PREMULTIPLIED);
@@ -209,6 +210,7 @@ gsk_vulkan_frame_upload_texture (GskGpuFrame *frame,
image = gsk_vulkan_image_new_for_dmabuf (GSK_VULKAN_DEVICE (gsk_gpu_frame_get_device (frame)),
gdk_texture_get_width (texture),
gdk_texture_get_height (texture),
gdk_texture_get_color_state (texture),
gdk_dmabuf_texture_get_dmabuf (GDK_DMABUF_TEXTURE (texture)),
gdk_memory_format_alpha (gdk_texture_get_format (texture)) == GDK_MEMORY_ALPHA_PREMULTIPLIED);
if (image)

View File

@@ -844,6 +844,7 @@ GskGpuImage *
gsk_vulkan_image_new_for_dmabuf (GskVulkanDevice *device,
gsize width,
gsize height,
GdkColorState *color_state,
const GdkDmabuf *dmabuf,
gboolean premultiplied)
{
@@ -859,6 +860,7 @@ gsk_vulkan_image_new_for_dmabuf (GskVulkanDevice *device,
GdkMemoryFormat format;
GskGpuImageFlags flags;
gboolean is_yuv;
const GdkCicp *cicp;
if (!gsk_vulkan_device_has_feature (device, GDK_VULKAN_FEATURE_DMABUF))
{
@@ -968,13 +970,36 @@ gsk_vulkan_image_new_for_dmabuf (GskVulkanDevice *device,
return NULL;
}
gsk_gpu_image_setup (GSK_GPU_IMAGE (self),
flags |
(gdk_memory_format_alpha (format) == GDK_MEMORY_ALPHA_STRAIGHT ? GSK_GPU_IMAGE_STRAIGHT_ALPHA : 0) |
(is_yuv ? (GSK_GPU_IMAGE_EXTERNAL | GSK_GPU_IMAGE_NO_BLIT) : 0) |
(gsk_component_mapping_is_framebuffer_compatible (&vk_components) ? 0 : GSK_GPU_IMAGE_NO_BLIT),
format,
width, height);
if (is_yuv)
flags |= GSK_GPU_IMAGE_EXTERNAL | GSK_GPU_IMAGE_NO_BLIT;
if (gdk_memory_format_alpha (format) == GDK_MEMORY_ALPHA_STRAIGHT)
flags |= GSK_GPU_IMAGE_STRAIGHT_ALPHA;
if (!gsk_component_mapping_is_framebuffer_compatible (&vk_components))
flags |= GSK_GPU_IMAGE_NO_BLIT;
cicp = gdk_color_state_get_cicp (color_state);
switch (cicp->matrix_coefficients)
{
case 1:
flags |= GSK_GPU_IMAGE_BT709;
break;
case 5:
case 6:
flags |= GSK_GPU_IMAGE_BT601;
break;
case 9:
flags |= GSK_GPU_IMAGE_BT2020;
break;
default:
break;
}
if (cicp->range == GDK_CICP_RANGE_NARROW)
flags |= GSK_GPU_IMAGE_NARROW_RANGE;
gsk_gpu_image_setup (GSK_GPU_IMAGE (self), flags, format, width, height);
self->allocator = gsk_vulkan_device_get_external_allocator (device);
gsk_vulkan_allocator_ref (self->allocator);

View File

@@ -42,6 +42,7 @@ GskGpuImage * gsk_vulkan_image_new_dmabuf (GskVulk
GskGpuImage * gsk_vulkan_image_new_for_dmabuf (GskVulkanDevice *device,
gsize width,
gsize height,
GdkColorState *color_state,
const GdkDmabuf *dmabuf,
gboolean premultiplied);
GdkTexture * gsk_vulkan_image_to_dmabuf_texture (GskVulkanImage *self);

View File

@@ -14,6 +14,8 @@ PASS(2) vec2 _tex_coord;
PASS_FLAT(3) float _opacity;
PASS_FLAT(4) uint _transfer_function;
PASS_FLAT(5) mat3 _mat;
PASS_FLAT(8) mat3 _yuv;
PASS_FLAT(11) uint _range;
#ifdef GSK_VERTEX_SHADER
@@ -22,6 +24,8 @@ IN(1) vec4 in_tex_rect;
IN(2) float in_opacity;
IN(3) uint in_color_primaries;
IN(4) uint in_transfer_function;
IN(5) uint in_matrix_coefficients;
IN(6) uint in_range;
const mat3 identity = mat3(
@@ -90,6 +94,42 @@ const mat3 xyz_to_p3 = mat3(
-0.4027108, 0.0236247, 0.9568845
);
const mat3 rgb_to_bt601 = mat3(
0.299000, -0.168736, 0.500000,
0.587000, -0.331264, -0.418688,
0.114000, 0.500000, -0.081312
);
const mat3 bt601_to_rgb = mat3(
1.000000, 1.000000, 1.000000,
0.000000, -0.344136, 1.772000,
1.402000, -0.714136, 0.000000
);
const mat3 rgb_to_bt709 = mat3(
0.212600, -0.114572, 0.500000,
0.715200, -0.385428, -0.454153,
0.072200, 0.500000, -0.045847
);
const mat3 bt709_to_rgb = mat3(
1.000000, 1.000000, 1.000000,
0.000000, -0.187324, 1.855600,
1.574800, -0.468124, -0.000000
);
const mat3 rgb_to_bt2020 = mat3(
0.262700, -0.139630, 0.500000,
0.678000, -0.360370, -0.459786,
0.059300, 0.500000, -0.040214
);
const mat3 bt2020_to_rgb = mat3(
1.000000, 1.000000, 1.000000,
-0.000000, -0.164553, 1.881400,
1.474600, -0.571353, -0.000000
);
mat3
cicp_to_xyz (uint cp)
{
@@ -121,6 +161,34 @@ cicp_from_xyz (uint cp)
}
mat3
yuv_to_rgb (uint mc)
{
switch (mc)
{
case 0u: return identity;
case 1u: return bt709_to_rgb;
case 5u:
case 6u: return bt601_to_rgb;
case 9u: return bt2020_to_rgb;
}
return mat3(0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0);
}
mat3
rgb_to_yuv (uint mc)
{
switch (mc)
{
case 0u: return identity;
case 1u: return rgb_to_bt709;
case 5u:
case 6u: return rgb_to_bt601;
case 9u: return rgb_to_bt2020;
}
return mat3(0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0);
}
void
run (out vec2 pos)
{
@@ -133,6 +201,7 @@ run (out vec2 pos)
_tex_coord = rect_get_coord (rect_from_gsk (in_tex_rect), pos);
_opacity = in_opacity;
_transfer_function = in_transfer_function;
_range = in_range;
if (HAS_VARIATION (VARIATION_REVERSE))
{
@@ -141,6 +210,8 @@ run (out vec2 pos)
_mat = cicp_from_xyz (in_color_primaries) * srgb_to_xyz;
else
_mat = cicp_from_xyz (in_color_primaries) * rec2020_to_xyz;
_yuv = rgb_to_yuv (in_matrix_coefficients);
}
else
{
@@ -149,6 +220,8 @@ run (out vec2 pos)
_mat = xyz_to_srgb * cicp_to_xyz (in_color_primaries);
else
_mat = xyz_to_rec2020 * cicp_to_xyz (in_color_primaries);
_yuv = yuv_to_rgb (in_matrix_coefficients);
}
}
@@ -329,6 +402,18 @@ convert_color_from_cicp (vec4 color,
if (from_premul)
color = color_unpremultiply (color);
if (_range == 0u)
{
color.r = (color.r - 16.0/255.0) * 255.0/219.0;
color.g = (color.g - 16.0/255.0) * 255.0/224.0;
color.b = (color.b - 16.0/255.0) * 255.0/224.0;
}
color.g -= 0.5;
color.b -= 0.5;
color.rgb = _yuv * color.rgb;
color.rgb = apply_cicp_eotf (color.rgb, _transfer_function);
color.rgb = _mat * color.rgb;
color.rgb = apply_oetf (color.rgb, to);
@@ -352,6 +437,18 @@ convert_color_to_cicp (vec4 color,
color.rgb = _mat * color.rgb;
color.rgb = apply_cicp_oetf (color.rgb, _transfer_function);
color.rgb = _yuv * color.rgb;
color.g += 0.5;
color.b += 0.5;
if (_range == 0u)
{
color.r = color.r * 219.0/255.0 + 16.0/255.0;
color.g = color.g * 224.0/255.0 + 16.0/255.0;
color.b = color.b * 224.0/255.0 + 16.0/255.0;
}
if (to_premul)
color = color_premultiply (color);

View File

@@ -24,6 +24,8 @@
#include "gtkgstpaintableprivate.h"
#include "gdk/gdkdmabuffourccprivate.h"
#if GST_GL_HAVE_WINDOW_X11 && (GST_GL_HAVE_PLATFORM_GLX || GST_GL_HAVE_PLATFORM_EGL) && defined (GDK_WINDOWING_X11)
#define HAVE_GST_X11_SUPPORT
#include <gdk/x11/gdkx.h>
@@ -168,7 +170,8 @@ add_drm_formats_and_modifiers (GstCaps *caps,
static GdkColorState *
gtk_gst_color_state_from_colorimetry (GtkGstSink *self,
const GstVideoColorimetry *colorimetry)
const GstVideoColorimetry *colorimetry,
gconstpointer drm)
{
GdkCicpParams *params;
GdkColorState *color_state;
@@ -186,18 +189,92 @@ gtk_gst_color_state_from_colorimetry (GtkGstSink *self,
else
gdk_cicp_params_set_transfer_function (params, gst_video_transfer_function_to_iso (colorimetry->transfer));
#if 0
gdk_cicp_params_set_range (params, colorimetry->range == GST_VIDEO_COLOR_RANGE_16_235 ? GDK_CICP_RANGE_NARROW : GDK_CICP_RANGE_FULL);
if (colorimetry->matrix == GST_VIDEO_COLOR_MATRIX_UNKNOWN)
gdk_cicp_params_set_matrix_coefficients (params, 6);
{
gdk_cicp_params_set_matrix_coefficients (params, 0);
#ifdef HAVE_GSTREAMER_DRM
const GstVideoInfoDmaDrm *drm_info = drm;
if (drm_info)
{
switch (drm_info->drm_fourcc)
{
case DRM_FORMAT_YUYV:
case DRM_FORMAT_YVYU:
case DRM_FORMAT_VYUY:
case DRM_FORMAT_UYVY:
case DRM_FORMAT_AYUV:
case DRM_FORMAT_AVUY8888:
case DRM_FORMAT_XYUV8888:
case DRM_FORMAT_XVUY8888:
case DRM_FORMAT_VUY888:
case DRM_FORMAT_VUY101010:
case DRM_FORMAT_Y210:
case DRM_FORMAT_Y212:
case DRM_FORMAT_Y216:
case DRM_FORMAT_Y410:
case DRM_FORMAT_Y412:
case DRM_FORMAT_Y416:
case DRM_FORMAT_XVYU2101010:
case DRM_FORMAT_XVYU12_16161616:
case DRM_FORMAT_XVYU16161616:
case DRM_FORMAT_Y0L0:
case DRM_FORMAT_X0L0:
case DRM_FORMAT_Y0L2:
case DRM_FORMAT_X0L2:
case DRM_FORMAT_YUV420_8BIT:
case DRM_FORMAT_YUV420_10BIT:
case DRM_FORMAT_NV12:
case DRM_FORMAT_NV21:
case DRM_FORMAT_NV16:
case DRM_FORMAT_NV61:
case DRM_FORMAT_NV24:
case DRM_FORMAT_NV42:
case DRM_FORMAT_NV15:
case DRM_FORMAT_P210:
case DRM_FORMAT_P010:
case DRM_FORMAT_P012:
case DRM_FORMAT_P016:
case DRM_FORMAT_P030:
case DRM_FORMAT_Q410:
case DRM_FORMAT_Q401:
case DRM_FORMAT_YUV410:
case DRM_FORMAT_YVU410:
case DRM_FORMAT_YUV411:
case DRM_FORMAT_YVU411:
case DRM_FORMAT_YUV420:
case DRM_FORMAT_YVU420:
case DRM_FORMAT_YUV422:
case DRM_FORMAT_YVU422:
case DRM_FORMAT_YUV444:
case DRM_FORMAT_YVU444:
g_debug ("Assuming fourcc %.*s is yuv", 4, (char *)&drm_info->drm_fourcc);
gdk_cicp_params_set_matrix_coefficients (params, 6);
gdk_cicp_params_set_range (params, GDK_CICP_RANGE_NARROW);
break;
default:
break;
}
}
#endif
}
else
gdk_cicp_params_set_matrix_coefficients (params, gst_video_color_matrix_to_iso (colorimetry->matrix));
gdk_cicp_params_set_range (params, colorimetry->range == GST_VIDEO_COLOR_RANGE_0_255 ? GDK_CICP_RANGE_FULL : GDK_CICP_RANGE_NARROW);
#else
gdk_cicp_params_set_matrix_coefficients (params, 0);
gdk_cicp_params_set_range (params, GDK_CICP_RANGE_FULL);
#endif
color_state = gdk_cicp_params_build_color_state (params, &error);
g_debug ("cicp received: %u/%u/%u/%u",
gst_video_color_primaries_to_iso (colorimetry->primaries),
gst_video_transfer_function_to_iso (colorimetry->transfer),
gst_video_color_matrix_to_iso (colorimetry->matrix),
colorimetry->range == GST_VIDEO_COLOR_RANGE_0_255);
g_debug ("cicp used: %u/%u/%u/%u",
gdk_cicp_params_get_color_primaries (params),
gdk_cicp_params_get_transfer_function (params),
gdk_cicp_params_get_matrix_coefficients (params),
gdk_cicp_params_get_range (params));
g_object_unref (params);
if (color_state == NULL)
@@ -281,7 +358,14 @@ gtk_gst_sink_set_caps (GstBaseSink *bsink,
#endif
g_clear_pointer (&self->color_state, gdk_color_state_unref);
self->color_state = gtk_gst_color_state_from_colorimetry (self, &self->v_info.colorimetry);
self->color_state = gtk_gst_color_state_from_colorimetry (self,
&self->v_info.colorimetry,
#ifdef HAVE_GSTREAMER_DRM
&self->drm_info
#else
NULL
#endif
);
if (self->color_state == NULL)
return FALSE;

View File

@@ -48,6 +48,9 @@ static MatrixTest matrices[] = {
{ "ntsc", ntsc_to_xyz, xyz_to_ntsc },
{ "p3", p3_to_xyz, xyz_to_p3 },
{ "srgb<>rec2020", rec2020_to_srgb, srgb_to_rec2020 },
{ "bt601", bt601_to_rgb, rgb_to_bt601 },
{ "bt709", bt709_to_rgb, rgb_to_bt709 },
{ "bt2020", bt2020_to_rgb, rgb_to_bt2020 },
};
#define IDX(i,j) 3*i+j

View File

@@ -127,9 +127,11 @@ test_convert (gconstpointer testdata)
gsize width, height;
GdkMemoryFormat test_format;
#if 0
if (g_test_rand_bit ())
test_format = GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED;
else
#endif
test_format = GDK_MEMORY_R32G32B32A32_FLOAT;
path = g_test_build_filename (G_TEST_DIST, "image-data", "image.png", NULL);

View File

@@ -5,6 +5,7 @@
#include <gdk/gdkglcontextprivate.h>
#include <gdk/gdkdmabuffourccprivate.h>
#include <gdk/gdkdmabuftextureprivate.h>
#include <gdk/gdkdmabufeglprivate.h>
static cairo_surface_t *
make_surface (int width,
@@ -191,6 +192,8 @@ test_dmabuf_import (void)
GdkGLTextureBuilder *builder;
guchar *data;
gboolean external;
GdkColorState *color_state;
int color_space, range;
display = gdk_display_get_default ();
if (!gdk_display_prepare_gl (display, &error))
@@ -229,7 +232,9 @@ test_dmabuf_import (void)
g_assert_no_error (error);
dmabuf2 = gdk_dmabuf_texture_get_dmabuf (GDK_DMABUF_TEXTURE (texture));
texture_id2 = gdk_gl_context_import_dmabuf (context2, 64, 64, dmabuf2, &external);
color_state = gdk_texture_get_color_state (texture);
gdk_dmabuf_get_egl_yuv_hints (dmabuf2, color_state, &color_space, &range);
texture_id2 = gdk_gl_context_import_dmabuf (context2, 64, 64, dmabuf2, color_space, range, &external);
g_assert_cmpint (texture_id2, !=, 0);
g_assert_false (external);

View File

@@ -4,6 +4,7 @@
#include <gtk/gtk.h>
#include <stdlib.h>
#include "../reftests/reftest-compare.h"
#include "dmabufize.h"
static char *arg_output_dir = NULL;
@@ -15,6 +16,7 @@ static gboolean mask = FALSE;
static gboolean replay = FALSE;
static gboolean clip = FALSE;
static gboolean colorflip = FALSE;
static gboolean dmabuf = FALSE;
extern void
replay_node (GskRenderNode *node, GtkSnapshot *snapshot);
@@ -172,6 +174,7 @@ static const GOptionEntry options[] = {
{ "replay", 0, 0, G_OPTION_ARG_NONE, &replay, "Do replay test", NULL },
{ "clip", 0, 0, G_OPTION_ARG_NONE, &clip, "Do clip test", NULL },
{ "colorflip", 0, 0, G_OPTION_ARG_NONE, &colorflip, "Swap colors", NULL },
{ "dmabuf", 0, 0, G_OPTION_ARG_NONE, &dmabuf, "Turn into dmabufs", NULL },
{ NULL }
};
@@ -728,6 +731,37 @@ skip_clip:
gsk_render_node_unref (node2);
}
if (dmabuf)
{
GskRenderNode *node2;
graphene_rect_t node_bounds;
gsk_render_node_get_bounds (node, &node_bounds);
node2 = dmabufize_node (node);
save_node (node2, node_file, "-dmabuf.node");
rendered_texture = gsk_renderer_render_texture (renderer, node2, NULL);
save_image (rendered_texture, node_file, "-dmabuf.out.png");
reference_texture = gsk_renderer_render_texture (renderer, node, &node_bounds);
save_image (reference_texture, node_file, "-dmabuf.ref.png");
diff_texture = reftest_compare_textures (rendered_texture, reference_texture);
if (diff_texture)
{
save_image (diff_texture, node_file, "-dmabuf.diff.png");
success = FALSE;
}
g_clear_object (&diff_texture);
g_clear_object (&rendered_texture);
g_clear_object (&reference_texture);
gsk_render_node_unref (node2);
}
gsk_render_node_unref (node);
gsk_renderer_unrealize (renderer);
g_object_unref (renderer);

439
testsuite/gsk/dmabufize.c Normal file
View File

@@ -0,0 +1,439 @@
#include "config.h"
#include <gtk/gtk.h>
#include "udmabuf.h"
#include "dmabufize.h"
#ifdef HAVE_DMABUF
#include <drm_fourcc.h>
static GdkTexture *
dmabufize_texture (GdkTexture *texture)
{
guint32 fourcc = 0;
guint32 bpp;
gboolean premultiplied;
gsize width;
gsize height;
gsize size;
UDmabuf *udmabuf;
GdkTextureDownloader *downloader;
GdkDmabufTextureBuilder *builder;
GdkTexture *texture2;
if (strcmp (G_OBJECT_TYPE_NAME (texture), "GdkMemoryTexture") != 0)
return g_object_ref (texture);
switch ((int) gdk_texture_get_format (texture))
{
case GDK_MEMORY_B8G8R8A8_PREMULTIPLIED:
fourcc = DRM_FORMAT_ARGB8888;
premultiplied = TRUE;
bpp = 4;
break;
case GDK_MEMORY_A8R8G8B8_PREMULTIPLIED:
fourcc = DRM_FORMAT_BGRA8888;
premultiplied = TRUE;
bpp = 4;
break;
case GDK_MEMORY_R8G8B8A8_PREMULTIPLIED:
fourcc = DRM_FORMAT_ABGR8888;
premultiplied = TRUE;
bpp = 4;
break;
case GDK_MEMORY_A8B8G8R8_PREMULTIPLIED:
fourcc = DRM_FORMAT_RGBA8888;
premultiplied = TRUE;
bpp = 4;
break;
case GDK_MEMORY_B8G8R8A8:
fourcc = DRM_FORMAT_ARGB8888;
premultiplied = FALSE;
bpp = 4;
break;
case GDK_MEMORY_A8R8G8B8:
fourcc = DRM_FORMAT_BGRA8888;
premultiplied = FALSE;
bpp = 4;
break;
default:
break;
}
if (fourcc == 0)
return g_object_ref (texture);
width = gdk_texture_get_width (texture);
height = gdk_texture_get_height (texture);
size = height * width * bpp;
udmabuf = udmabuf_allocate (size, NULL);
downloader = gdk_texture_downloader_new (texture);
gdk_texture_downloader_set_format (downloader, gdk_texture_get_format (texture));
gdk_texture_downloader_set_color_state (downloader, gdk_texture_get_color_state (texture));
gdk_texture_downloader_download_into (downloader, (guchar *)udmabuf->data, width * bpp);
gdk_texture_downloader_free (downloader);
builder = gdk_dmabuf_texture_builder_new ();
gdk_dmabuf_texture_builder_set_display (builder, gdk_display_get_default ());
gdk_dmabuf_texture_builder_set_width (builder, width);
gdk_dmabuf_texture_builder_set_height (builder, height);
gdk_dmabuf_texture_builder_set_fourcc (builder, fourcc);
gdk_dmabuf_texture_builder_set_modifier (builder, 0);
gdk_dmabuf_texture_builder_set_premultiplied (builder, premultiplied);
gdk_dmabuf_texture_builder_set_n_planes (builder, 1);
gdk_dmabuf_texture_builder_set_fd (builder, 0, udmabuf->dmabuf_fd);
gdk_dmabuf_texture_builder_set_stride (builder, 0, width * bpp);
gdk_dmabuf_texture_builder_set_offset (builder, 0, 0);
gdk_dmabuf_texture_builder_set_color_state (builder, gdk_texture_get_color_state (texture));
texture2 = gdk_dmabuf_texture_builder_build (builder, udmabuf_free, udmabuf, NULL);
g_object_unref (builder);
return texture2;
}
static GskRenderNode *
dmabufize_container_node (GskRenderNode *node)
{
guint n_nodes;
GskRenderNode **nodes;
n_nodes = gsk_container_node_get_n_children (node);
nodes = g_newa (GskRenderNode *, n_nodes);
for (int i = 0; i < n_nodes; i++)
nodes[i] = dmabufize_node (gsk_container_node_get_child (node, i));
node = gsk_container_node_new (nodes, n_nodes);
for (int i = 0; i < n_nodes; i++)
gsk_render_node_unref (nodes[i]);
return node;
}
static GskRenderNode *
dmabufize_texture_node (GskRenderNode *node)
{
GdkTexture *texture = gsk_texture_node_get_texture (node);
graphene_rect_t bounds;
gsk_render_node_get_bounds (node, &bounds);
texture = dmabufize_texture (texture);
node = gsk_texture_node_new (texture, &bounds);
g_object_unref (texture);
return node;
}
static GskRenderNode *
dmabufize_texture_scale_node (GskRenderNode *node)
{
GdkTexture *texture = gsk_texture_scale_node_get_texture (node);
graphene_rect_t bounds;
gsk_render_node_get_bounds (node, &bounds);
texture = dmabufize_texture (texture);
node = gsk_texture_scale_node_new (texture, &bounds, gsk_texture_scale_node_get_filter (node));
g_object_unref (texture);
return node;
}
static GskRenderNode *
dmabufize_transform_node (GskRenderNode *node)
{
GskRenderNode *child = gsk_transform_node_get_child (node);
child = dmabufize_node (child);
node = gsk_transform_node_new (child, gsk_transform_node_get_transform (node));
gsk_render_node_unref (child);
return node;
}
static GskRenderNode *
dmabufize_opacity_node (GskRenderNode *node)
{
GskRenderNode *child = gsk_opacity_node_get_child (node);
child = dmabufize_node (child);
node = gsk_opacity_node_new (child, gsk_opacity_node_get_opacity (node));
gsk_render_node_unref (child);
return node;
}
static GskRenderNode *
dmabufize_color_matrix_node (GskRenderNode *node)
{
GskRenderNode *child = gsk_color_matrix_node_get_child (node);
child = dmabufize_node (child);
node = gsk_color_matrix_node_new (child, gsk_color_matrix_node_get_color_matrix (node),
gsk_color_matrix_node_get_color_offset (node));
gsk_render_node_unref (child);
return node;
}
static GskRenderNode *
dmabufize_repeat_node (GskRenderNode *node)
{
GskRenderNode *child = gsk_repeat_node_get_child (node);
graphene_rect_t bounds;
gsk_render_node_get_bounds (node, &bounds);
child = dmabufize_node (child);
node = gsk_repeat_node_new (&bounds,
child,
gsk_repeat_node_get_child_bounds (node));
gsk_render_node_unref (child);
return node;
}
static GskRenderNode *
dmabufize_clip_node (GskRenderNode *node)
{
GskRenderNode *child = gsk_clip_node_get_child (node);
child = dmabufize_node (child);
node = gsk_clip_node_new (child, gsk_clip_node_get_clip (node));
gsk_render_node_unref (child);
return node;
}
static GskRenderNode *
dmabufize_rounded_clip_node (GskRenderNode *node)
{
GskRenderNode *child = gsk_rounded_clip_node_get_child (node);
child = dmabufize_node (child);
node = gsk_rounded_clip_node_new (child, gsk_rounded_clip_node_get_clip (node));
gsk_render_node_unref (child);
return node;
}
static GskRenderNode *
dmabufize_shadow_node (GskRenderNode *node)
{
GskRenderNode *child = gsk_shadow_node_get_child (node);
child = dmabufize_node (child);
node = gsk_shadow_node_new (child,
gsk_shadow_node_get_shadow (node, 0),
gsk_shadow_node_get_n_shadows (node));
gsk_render_node_unref (child);
return node;
}
static GskRenderNode *
dmabufize_blend_node (GskRenderNode *node)
{
GskRenderNode *top = gsk_blend_node_get_top_child (node);
GskRenderNode *bottom = gsk_blend_node_get_bottom_child (node);
top = dmabufize_node (top);
bottom = dmabufize_node (bottom);
node = gsk_blend_node_new (bottom, top, gsk_blend_node_get_blend_mode (node));
gsk_render_node_unref (top);
gsk_render_node_unref (bottom);
return node;
}
static GskRenderNode *
dmabufize_cross_fade_node (GskRenderNode *node)
{
GskRenderNode *start = gsk_cross_fade_node_get_start_child (node);
GskRenderNode *end = gsk_cross_fade_node_get_end_child (node);
start = dmabufize_node (start);
end = dmabufize_node (end);
node = gsk_cross_fade_node_new (start, end, gsk_cross_fade_node_get_progress (node));
gsk_render_node_unref (start);
gsk_render_node_unref (end);
return node;
}
static GskRenderNode *
dmabufize_blur_node (GskRenderNode *node)
{
GskRenderNode *child = gsk_blur_node_get_child (node);
child = dmabufize_node (child);
node = gsk_blur_node_new (child, gsk_blur_node_get_radius (node));
gsk_render_node_unref (child);
return node;
}
static GskRenderNode *
dmabufize_debug_node (GskRenderNode *node)
{
GskRenderNode *child = gsk_debug_node_get_child (node);
child = dmabufize_node (child);
node = gsk_debug_node_new (child, (char *)gsk_debug_node_get_message (node));
gsk_render_node_unref (child);
return node;
}
static GskRenderNode *
dmabufize_mask_node (GskRenderNode *node)
{
GskRenderNode *source = gsk_mask_node_get_source (node);
GskRenderNode *mask = gsk_mask_node_get_mask (node);
source = dmabufize_node (source);
mask = dmabufize_node (mask);
node = gsk_mask_node_new (source, mask, gsk_mask_node_get_mask_mode (node));
gsk_render_node_unref (source);
gsk_render_node_unref (mask);
return node;
}
static GskRenderNode *
dmabufize_fill_node (GskRenderNode *node)
{
GskRenderNode *child = gsk_fill_node_get_child (node);
child = dmabufize_node (child);
node = gsk_fill_node_new (child, gsk_fill_node_get_path (node), gsk_fill_node_get_fill_rule (node));
gsk_render_node_unref (child);
return node;
}
static GskRenderNode *
dmabufize_stroke_node (GskRenderNode *node)
{
GskRenderNode *child = gsk_stroke_node_get_child (node);
child = dmabufize_node (child);
node = gsk_stroke_node_new (child, gsk_stroke_node_get_path (node), gsk_stroke_node_get_stroke (node));
gsk_render_node_unref (child);
return node;
}
static GskRenderNode *
dmabufize_subsurface_node (GskRenderNode *node)
{
GskRenderNode *child = gsk_subsurface_node_get_child (node);
child = dmabufize_node (child);
node = gsk_subsurface_node_new (child, gsk_subsurface_node_get_subsurface (node));
gsk_render_node_unref (child);
return node;
}
GskRenderNode *
dmabufize_node (GskRenderNode *node)
{
switch (gsk_render_node_get_node_type (node))
{
case GSK_CONTAINER_NODE:
return dmabufize_container_node (node);
case GSK_CAIRO_NODE:
case GSK_COLOR_NODE:
case GSK_LINEAR_GRADIENT_NODE:
case GSK_REPEATING_LINEAR_GRADIENT_NODE:
case GSK_RADIAL_GRADIENT_NODE:
case GSK_REPEATING_RADIAL_GRADIENT_NODE:
case GSK_CONIC_GRADIENT_NODE:
case GSK_BORDER_NODE:
case GSK_INSET_SHADOW_NODE:
case GSK_OUTSET_SHADOW_NODE:
case GSK_TEXT_NODE:
case GSK_GL_SHADER_NODE:
return gsk_render_node_ref (node);
case GSK_TEXTURE_NODE:
return dmabufize_texture_node (node);
case GSK_TEXTURE_SCALE_NODE:
return dmabufize_texture_scale_node (node);
case GSK_TRANSFORM_NODE:
return dmabufize_transform_node (node);
case GSK_OPACITY_NODE:
return dmabufize_opacity_node (node);
case GSK_COLOR_MATRIX_NODE:
return dmabufize_color_matrix_node (node);
case GSK_REPEAT_NODE:
return dmabufize_repeat_node (node);
case GSK_CLIP_NODE:
return dmabufize_clip_node (node);
case GSK_ROUNDED_CLIP_NODE:
return dmabufize_rounded_clip_node (node);
case GSK_SHADOW_NODE:
return dmabufize_shadow_node (node);
case GSK_BLEND_NODE:
return dmabufize_blend_node (node);
case GSK_CROSS_FADE_NODE:
return dmabufize_cross_fade_node (node);
case GSK_BLUR_NODE:
return dmabufize_blur_node (node);
case GSK_DEBUG_NODE:
return dmabufize_debug_node (node);
case GSK_MASK_NODE:
return dmabufize_mask_node (node);
case GSK_FILL_NODE:
return dmabufize_fill_node (node);
case GSK_STROKE_NODE:
return dmabufize_stroke_node (node);
case GSK_SUBSURFACE_NODE:
return dmabufize_subsurface_node (node);
case GSK_NOT_A_RENDER_NODE:
default:
g_assert_not_reached ();
}
}
#else
GskRenderNode *
dmabufize_node (GskRenderNode *node)
{
return gsk_render_node_ref (node);
}
#endif

View File

@@ -0,0 +1,3 @@
#pragma once
GskRenderNode * dmabufize_node (GskRenderNode *node);

View File

@@ -1,5 +1,5 @@
compare_render = executable('compare-render',
['compare-render.c', '../reftests/reftest-compare.c', 'replay-node.c'],
['compare-render.c', '../reftests/reftest-compare.c', 'replay-node.c', 'udmabuf.c', 'dmabufize.c' ],
dependencies: libgtk_dep,
c_args: common_cflags,
)

149
testsuite/gsk/udmabuf.c Normal file
View File

@@ -0,0 +1,149 @@
#include "config.h"
#ifdef HAVE_DMABUF
#include "udmabuf.h"
#include <inttypes.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <linux/udmabuf.h>
#include <drm_fourcc.h>
#include <errno.h>
#include <gio/gio.h>
static int udmabuf_fd;
gboolean
udmabuf_initialize (GError **error)
{
if (udmabuf_fd == 0)
{
udmabuf_fd = open ("/dev/udmabuf", O_RDWR);
if (udmabuf_fd == -1)
{
g_set_error (error,
G_IO_ERROR, G_IO_ERROR_FAILED,
"Failed to open /dev/udmabuf: %s",
g_strerror (errno));
}
}
return udmabuf_fd != -1;
}
void
udmabuf_free (gpointer data)
{
UDmabuf *udmabuf = data;
munmap (udmabuf->data, udmabuf->size);
close (udmabuf->mem_fd);
close (udmabuf->dmabuf_fd);
g_free (udmabuf);
}
#define align(x,y) (((x) + (y) - 1) & ~((y) - 1))
UDmabuf *
udmabuf_allocate (size_t size,
GError **error)
{
int mem_fd = -1;
int dmabuf_fd = -1;
uint64_t alignment;
int res;
gpointer data;
UDmabuf *udmabuf;
if (udmabuf_fd == -1)
{
g_set_error (error,
G_IO_ERROR, G_IO_ERROR_FAILED,
"udmabuf not available");
goto fail;
}
alignment = sysconf (_SC_PAGE_SIZE);
size = align (size, alignment);
mem_fd = memfd_create ("gtk", MFD_ALLOW_SEALING);
if (mem_fd == -1)
{
g_set_error (error,
G_IO_ERROR, G_IO_ERROR_FAILED,
"Failed to open /dev/udmabuf: %s",
g_strerror (errno));
goto fail;
}
res = ftruncate (mem_fd, size);
if (res == -1)
{
g_set_error (error,
G_IO_ERROR, G_IO_ERROR_FAILED,
"ftruncate failed: %s",
g_strerror (errno));
goto fail;
}
if (fcntl (mem_fd, F_ADD_SEALS, F_SEAL_SHRINK) < 0)
{
g_set_error (error,
G_IO_ERROR, G_IO_ERROR_FAILED,
"ftruncate failed: %s",
g_strerror (errno));
goto fail;
}
dmabuf_fd = ioctl (udmabuf_fd,
UDMABUF_CREATE,
&(struct udmabuf_create) {
.memfd = mem_fd,
.flags = UDMABUF_FLAGS_CLOEXEC,
.offset = 0,
.size = size
});
if (dmabuf_fd < 0)
{
g_set_error (error,
G_IO_ERROR, G_IO_ERROR_FAILED,
"UDMABUF_CREATE ioctl failed: %s",
g_strerror (errno));
goto fail;
}
data = mmap (NULL, size, PROT_WRITE | PROT_READ, MAP_SHARED, mem_fd, 0);
if (!data)
{
g_set_error (error,
G_IO_ERROR, G_IO_ERROR_FAILED,
"mmap failed: %s",
g_strerror (errno));
goto fail;
}
udmabuf = g_new0 (UDmabuf, 1);
udmabuf->mem_fd = mem_fd;
udmabuf->dmabuf_fd = dmabuf_fd;
udmabuf->size = size;
udmabuf->data = data;
return udmabuf;
fail:
if (mem_fd != -1)
close (mem_fd);
if (dmabuf_fd != -1)
close (dmabuf_fd);
return NULL;
}
#endif

18
testsuite/gsk/udmabuf.h Normal file
View File

@@ -0,0 +1,18 @@
#pragma once
#include <glib.h>
typedef struct
{
int mem_fd;
int dmabuf_fd;
size_t size;
gpointer data;
} UDmabuf;
void udmabuf_free (gpointer data);
gboolean udmabuf_initialize (GError **error);
UDmabuf *udmabuf_allocate (size_t size,
GError **error);