Compare commits
20 Commits
main
...
avif-suppo
Author | SHA1 | Date | |
---|---|---|---|
|
d4e536ebc6 | ||
|
00aec81d79 | ||
|
d536d4ab78 | ||
|
6d5664c4e3 | ||
|
8343ba9ce3 | ||
|
c68a189005 | ||
|
567de6317d | ||
|
502a7f201b | ||
|
0d33aafe9a | ||
|
50e7f02fc4 | ||
|
83ba577fa8 | ||
|
c53f791cb3 | ||
|
3445d2c12a | ||
|
22c119094c | ||
|
839095d968 | ||
|
1455933d61 | ||
|
406f563559 | ||
|
1a188e1171 | ||
|
c7780d7528 | ||
|
05e7b00453 |
@@ -265,6 +265,13 @@ support in the file chooser.
|
||||
This option controls whether GTK should use colord for color
|
||||
calibration support in the cups print backend.
|
||||
|
||||
## `avif`
|
||||
|
||||
This option controls whether GTK will use libavif for loading
|
||||
textures from AVIF image files. Note that the purpose of this option
|
||||
is to facilitate development of GTK. The support for this image format
|
||||
is not guaranteed and may go away at any time.
|
||||
|
||||
### `documentation`, `man-pages` and `screenshots`
|
||||
|
||||
The *gi-docgen* package is used to generate the reference documentation
|
||||
|
@@ -208,7 +208,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
|
||||
*/
|
||||
|
@@ -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,
|
||||
};
|
||||
|
@@ -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;
|
||||
@@ -688,6 +833,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;
|
||||
@@ -700,6 +873,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;
|
||||
|
||||
|
@@ -211,3 +211,10 @@ gdk_color_state_from_rgba (GdkColorState *self,
|
||||
out_color);
|
||||
}
|
||||
|
||||
#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)
|
||||
|
157
gdk/gdkdmabuf.c
@@ -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++)
|
||||
|
@@ -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 */
|
||||
|
@@ -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 */
|
||||
|
@@ -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,
|
||||
|
@@ -2198,6 +2198,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)
|
||||
@@ -2209,6 +2211,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;
|
||||
@@ -2232,6 +2236,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);
|
||||
@@ -2248,6 +2254,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)
|
||||
{
|
||||
@@ -2277,6 +2285,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)
|
||||
{
|
||||
@@ -2309,6 +2319,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)
|
||||
|
@@ -185,6 +185,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,
|
||||
|
@@ -983,6 +983,8 @@ gdk_texture_download_surface (GdkTexture *texture,
|
||||
* %CAIRO_FORMAT_ARGB32, so every downloaded pixel requires
|
||||
* 4 bytes of memory.
|
||||
*
|
||||
* The downloaded data is converted to the sRGB color state.
|
||||
*
|
||||
* Downloading a texture into a Cairo image surface:
|
||||
* ```c
|
||||
* surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
|
||||
|
865
gdk/loaders/gdkavif.c
Normal file
@@ -0,0 +1,865 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "gdkavifprivate.h"
|
||||
#include "gdkmemorytexturebuilder.h"
|
||||
#include "gdktexture.h"
|
||||
#include "gdkdisplay.h"
|
||||
#include "gdkcicpparamsprivate.h"
|
||||
#include "gdkcolorstateprivate.h"
|
||||
#include "gdkmemoryformatprivate.h"
|
||||
#include "gdkdmabuftexture.h"
|
||||
#include "gdktexturedownloader.h"
|
||||
|
||||
#include <avif/avif.h>
|
||||
|
||||
#ifdef HAVE_DMABUF
|
||||
|
||||
#include "gdkdmabuftextureprivate.h"
|
||||
#include "gdkdmabuftexturebuilder.h"
|
||||
#include "gdkdmabuffourccprivate.h"
|
||||
|
||||
/* NOTE: We build this code outside of libgtk, in tests and the image tool, so this
|
||||
* code has to be a bit careful to avoid depending on private api, which can also
|
||||
* be dragged in indirectly, via inlines.
|
||||
*/
|
||||
|
||||
#ifdef AVIF_DEBUG
|
||||
#define DEBUG(fmt,...) g_log ("avif", G_LOG_LEVEL_DEBUG, fmt __VA_OPT__(,) __VA_ARGS__)
|
||||
#else
|
||||
#define DEBUG(fmt,...)
|
||||
#endif
|
||||
|
||||
/* {{{ udmabuf support */
|
||||
|
||||
#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;
|
||||
|
||||
static 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;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int mem_fd;
|
||||
int dmabuf_fd;
|
||||
size_t size;
|
||||
gpointer data;
|
||||
} UDmabuf;
|
||||
|
||||
static 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))
|
||||
|
||||
static 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;
|
||||
}
|
||||
|
||||
/* }}} */
|
||||
/* {{{ dmabuf texture support */
|
||||
|
||||
static GdkTexture *
|
||||
gdk_avif_create_dmabuf_texture (avifDecoder *decoder,
|
||||
GdkColorState *color_state,
|
||||
GError **error)
|
||||
{
|
||||
guint fourcc = 0;
|
||||
guint32 width, height, depth;
|
||||
GdkDmabufTextureBuilder *builder;
|
||||
UDmabuf *udmabuf;
|
||||
gboolean combine_uv = FALSE;
|
||||
guchar *data;
|
||||
gsize size0, size1, size2;
|
||||
GdkTexture *texture;
|
||||
|
||||
if (!udmabuf_initialize (error))
|
||||
return NULL;
|
||||
|
||||
width = decoder->image->width;
|
||||
height = decoder->image->height;
|
||||
depth = decoder->image->depth;
|
||||
|
||||
if (decoder->image->alphaPlane)
|
||||
{
|
||||
g_set_error (error,
|
||||
GDK_TEXTURE_ERROR, GDK_TEXTURE_ERROR_UNSUPPORTED_CONTENT,
|
||||
"no yuv dmabuf with alpha");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch (decoder->image->yuvFormat)
|
||||
{
|
||||
case AVIF_PIXEL_FORMAT_YUV444:
|
||||
DEBUG ("load: format yuv444");
|
||||
if (depth == 8)
|
||||
fourcc = DRM_FORMAT_YUV444;
|
||||
break;
|
||||
case AVIF_PIXEL_FORMAT_YUV422:
|
||||
DEBUG ("load: format yuv422");
|
||||
if (depth == 8)
|
||||
fourcc = DRM_FORMAT_YUV422;
|
||||
break;
|
||||
case AVIF_PIXEL_FORMAT_YUV420:
|
||||
DEBUG ("load: format yuv420");
|
||||
combine_uv = TRUE;
|
||||
if (depth == 8)
|
||||
fourcc = DRM_FORMAT_NV12;
|
||||
else if (depth == 10)
|
||||
fourcc = DRM_FORMAT_P010;
|
||||
else if (depth == 12)
|
||||
fourcc = DRM_FORMAT_P012;
|
||||
else if (depth == 16)
|
||||
fourcc = DRM_FORMAT_P016;
|
||||
break;
|
||||
case AVIF_PIXEL_FORMAT_YUV400:
|
||||
case AVIF_PIXEL_FORMAT_NONE:
|
||||
case AVIF_PIXEL_FORMAT_COUNT:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (fourcc == 0)
|
||||
{
|
||||
const char *names[] = { "none", "yuv444", "yuv422", "yuv420", "yuv400" };
|
||||
|
||||
g_set_error (error,
|
||||
GDK_TEXTURE_ERROR, GDK_TEXTURE_ERROR_UNSUPPORTED_CONTENT,
|
||||
"unsupported pixel format %s, depth %u",
|
||||
names[decoder->image->yuvFormat], decoder->image->depth);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DEBUG ("load: use fourcc %.4s", (char *)&fourcc);
|
||||
|
||||
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_color_state (builder, color_state);
|
||||
gdk_dmabuf_texture_builder_set_fourcc (builder, fourcc);
|
||||
gdk_dmabuf_texture_builder_set_modifier (builder, DRM_FORMAT_MOD_LINEAR);
|
||||
gdk_dmabuf_texture_builder_set_premultiplied (builder, FALSE);
|
||||
|
||||
if (combine_uv)
|
||||
{
|
||||
size0 = height * avifImagePlaneRowBytes (decoder->image, AVIF_CHAN_Y);
|
||||
size1 = height / 2 * avifImagePlaneRowBytes (decoder->image, AVIF_CHAN_Y);
|
||||
|
||||
udmabuf = udmabuf_allocate (size0 + size1, NULL);
|
||||
|
||||
data = (guchar *) udmabuf->data;
|
||||
|
||||
if (depth == 8)
|
||||
{
|
||||
memcpy (data, avifImagePlane (decoder->image, AVIF_CHAN_Y), size0);
|
||||
for (int i = 0; i < height / 2; i++)
|
||||
{
|
||||
guchar *usrc = avifImagePlane (decoder->image, AVIF_CHAN_U) + i * avifImagePlaneRowBytes (decoder->image, AVIF_CHAN_U);
|
||||
guchar *vsrc = avifImagePlane (decoder->image, AVIF_CHAN_V) + i * avifImagePlaneRowBytes (decoder->image, AVIF_CHAN_V);
|
||||
guchar *dest = data + size0 + i * avifImagePlaneRowBytes (decoder->image, AVIF_CHAN_Y);
|
||||
for (int j = 0; j < width / 2; j++)
|
||||
{
|
||||
dest[2*j] = usrc[j];
|
||||
dest[2*j+1] = vsrc[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < height; i++)
|
||||
{
|
||||
guint16 *src = (guint16 *) (avifImagePlane (decoder->image, AVIF_CHAN_Y) + i * avifImagePlaneRowBytes (decoder->image, AVIF_CHAN_Y));
|
||||
guint16 *dest = (guint16 *) (data + i * avifImagePlaneRowBytes (decoder->image, AVIF_CHAN_Y));
|
||||
for (int j = 0; j < width; j++)
|
||||
dest[j] = src[j] << (16 - depth);
|
||||
}
|
||||
for (int i = 0; i < height / 2; i++)
|
||||
{
|
||||
guint16 *usrc = (guint16 *)(avifImagePlane (decoder->image, AVIF_CHAN_U) + i * avifImagePlaneRowBytes (decoder->image, AVIF_CHAN_U));
|
||||
guint16 *vsrc = (guint16 *)(avifImagePlane (decoder->image, AVIF_CHAN_V) + i * avifImagePlaneRowBytes (decoder->image, AVIF_CHAN_V));
|
||||
guint16 *dest = (guint16 *)(data + size0 + i * avifImagePlaneRowBytes (decoder->image, AVIF_CHAN_Y));
|
||||
for (int j = 0; j < width / 2; j++)
|
||||
{
|
||||
dest[2*j] = usrc[j] << (16 - depth);
|
||||
dest[2*j+1] = vsrc[j] << (16 - depth);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gdk_dmabuf_texture_builder_set_n_planes (builder, 2);
|
||||
|
||||
gdk_dmabuf_texture_builder_set_fd (builder, 0, udmabuf->dmabuf_fd);
|
||||
gdk_dmabuf_texture_builder_set_offset (builder, 0, 0);
|
||||
gdk_dmabuf_texture_builder_set_stride (builder, 0, avifImagePlaneRowBytes (decoder->image, AVIF_CHAN_Y));
|
||||
|
||||
gdk_dmabuf_texture_builder_set_fd (builder, 1, udmabuf->dmabuf_fd);
|
||||
gdk_dmabuf_texture_builder_set_offset (builder, 1, size0);
|
||||
gdk_dmabuf_texture_builder_set_stride (builder, 1, avifImagePlaneRowBytes (decoder->image, AVIF_CHAN_Y));
|
||||
}
|
||||
else
|
||||
{
|
||||
size0 = height * avifImagePlaneRowBytes (decoder->image, AVIF_CHAN_Y);
|
||||
size1 = height * avifImagePlaneRowBytes (decoder->image, AVIF_CHAN_U);
|
||||
size2 = height * avifImagePlaneRowBytes (decoder->image, AVIF_CHAN_V);
|
||||
|
||||
udmabuf = udmabuf_allocate (size0 + size1 + size2, NULL);
|
||||
|
||||
data = (guchar *) udmabuf->data;
|
||||
memcpy (data, avifImagePlane (decoder->image, AVIF_CHAN_Y), size0);
|
||||
memcpy (data + size0, avifImagePlane (decoder->image, AVIF_CHAN_U), size1);
|
||||
memcpy (data + size0 + size1, avifImagePlane (decoder->image, AVIF_CHAN_V), size2);
|
||||
|
||||
gdk_dmabuf_texture_builder_set_n_planes (builder, 3);
|
||||
|
||||
gdk_dmabuf_texture_builder_set_fd (builder, 0, udmabuf->dmabuf_fd);
|
||||
gdk_dmabuf_texture_builder_set_offset (builder, 0, 0);
|
||||
gdk_dmabuf_texture_builder_set_stride (builder, 0, avifImagePlaneRowBytes (decoder->image, AVIF_CHAN_Y));
|
||||
|
||||
gdk_dmabuf_texture_builder_set_fd (builder, 1, udmabuf->dmabuf_fd);
|
||||
gdk_dmabuf_texture_builder_set_offset (builder, 1, size0);
|
||||
gdk_dmabuf_texture_builder_set_stride (builder, 1, avifImagePlaneRowBytes (decoder->image, AVIF_CHAN_U));
|
||||
|
||||
gdk_dmabuf_texture_builder_set_fd (builder, 2, udmabuf->dmabuf_fd);
|
||||
gdk_dmabuf_texture_builder_set_offset (builder, 2, size0 + size1);
|
||||
gdk_dmabuf_texture_builder_set_stride (builder, 2, avifImagePlaneRowBytes (decoder->image, AVIF_CHAN_V));
|
||||
}
|
||||
|
||||
texture = gdk_dmabuf_texture_builder_build (builder, udmabuf_free, udmabuf, error);
|
||||
|
||||
g_object_unref (builder);
|
||||
|
||||
return texture;
|
||||
}
|
||||
#endif /* HAVE_DMABUF */
|
||||
|
||||
/* }}} */
|
||||
/* {{{ memory texture support */
|
||||
|
||||
static GdkTexture *
|
||||
gdk_avif_create_memory_texture (avifDecoder *decoder,
|
||||
GdkColorState *color_state,
|
||||
GError **error)
|
||||
{
|
||||
guint32 width, height, depth, stride, bpp;
|
||||
GdkTexture *texture;
|
||||
GdkMemoryTextureBuilder *builder;
|
||||
guchar *data;
|
||||
GBytes *bytes;
|
||||
GdkMemoryFormat format = GDK_MEMORY_N_FORMATS;
|
||||
int X_SUB, Y_SUB;
|
||||
|
||||
width = decoder->image->width;
|
||||
height = decoder->image->height;
|
||||
depth = decoder->image->depth;
|
||||
|
||||
switch (decoder->image->yuvFormat)
|
||||
{
|
||||
case AVIF_PIXEL_FORMAT_YUV444:
|
||||
X_SUB = 1; Y_SUB = 1;
|
||||
if (depth == 8)
|
||||
{
|
||||
format = GDK_MEMORY_R8G8B8A8;
|
||||
bpp = 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
format = GDK_MEMORY_R16G16B16A16;
|
||||
bpp = 8;
|
||||
}
|
||||
break;
|
||||
|
||||
case AVIF_PIXEL_FORMAT_YUV422:
|
||||
X_SUB = 2; Y_SUB = 1;
|
||||
if (depth == 8)
|
||||
{
|
||||
format = GDK_MEMORY_R8G8B8A8;
|
||||
bpp = 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
format = GDK_MEMORY_R16G16B16A16;
|
||||
bpp = 8;
|
||||
}
|
||||
break;
|
||||
|
||||
case AVIF_PIXEL_FORMAT_YUV420:
|
||||
X_SUB = 2; Y_SUB = 2;
|
||||
break;
|
||||
|
||||
case AVIF_PIXEL_FORMAT_YUV400:
|
||||
case AVIF_PIXEL_FORMAT_NONE:
|
||||
case AVIF_PIXEL_FORMAT_COUNT:
|
||||
if (depth == 8)
|
||||
{
|
||||
format = GDK_MEMORY_R8G8B8A8;
|
||||
bpp = 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
format = GDK_MEMORY_R16G16B16A16;
|
||||
bpp = 8;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (format == GDK_MEMORY_N_FORMATS)
|
||||
{
|
||||
const char *names[] = { "none", "yuv444", "yuv422", "yuv420", "yuv400" };
|
||||
|
||||
g_set_error (error,
|
||||
GDK_TEXTURE_ERROR, GDK_TEXTURE_ERROR_UNSUPPORTED_CONTENT,
|
||||
"unsupported pixel format for YUVA %s, depth %u",
|
||||
names[decoder->image->yuvFormat], depth);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
stride = width * bpp;
|
||||
data = g_malloc (stride * height);
|
||||
|
||||
if (depth == 8)
|
||||
{
|
||||
guchar *y_data = avifImagePlane (decoder->image, AVIF_CHAN_Y);
|
||||
guchar *u_data = avifImagePlane (decoder->image, AVIF_CHAN_U);
|
||||
guchar *v_data = avifImagePlane (decoder->image, AVIF_CHAN_V);
|
||||
guchar *a_data = avifImagePlane (decoder->image, AVIF_CHAN_A);
|
||||
guchar *dst_data = data;
|
||||
gsize y_stride = avifImagePlaneRowBytes (decoder->image, AVIF_CHAN_Y);
|
||||
gsize u_stride = avifImagePlaneRowBytes (decoder->image, AVIF_CHAN_U);
|
||||
gsize v_stride = avifImagePlaneRowBytes (decoder->image, AVIF_CHAN_V);
|
||||
gsize a_stride = avifImagePlaneRowBytes (decoder->image, AVIF_CHAN_A);
|
||||
gsize dst_stride = stride;
|
||||
|
||||
for (int y = 0; y < height; y += Y_SUB)
|
||||
{
|
||||
for (int x = 0; x < width; x += X_SUB)
|
||||
{
|
||||
guint y_, u_, v_, a_;
|
||||
|
||||
u_ = u_data[x / X_SUB];
|
||||
v_ = v_data[x / X_SUB];
|
||||
|
||||
for (int ys = 0; ys < Y_SUB && y + ys < height; ys++)
|
||||
for (int xs = 0; xs < X_SUB && x + xs < width; xs++)
|
||||
{
|
||||
guchar *dest = &dst_data[4 * (x + xs) + dst_stride * ys];
|
||||
|
||||
y_ = y_data[x + xs + y_stride * ys];
|
||||
a_ = a_data ? a_data[x + xs + a_stride * ys] : 0xff;
|
||||
|
||||
dest[0] = y_;
|
||||
dest[1] = u_;
|
||||
dest[2] = v_;
|
||||
dest[3] = a_;
|
||||
}
|
||||
}
|
||||
|
||||
dst_data += Y_SUB * dst_stride;
|
||||
y_data += Y_SUB * y_stride;
|
||||
u_data += u_stride;
|
||||
v_data += v_stride;
|
||||
if (a_data)
|
||||
a_data += a_stride;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
guint16 *y_data = (guint16 *) avifImagePlane (decoder->image, AVIF_CHAN_Y);
|
||||
guint16 *u_data = (guint16 *) avifImagePlane (decoder->image, AVIF_CHAN_U);
|
||||
guint16 *v_data = (guint16 *) avifImagePlane (decoder->image, AVIF_CHAN_V);
|
||||
guint16 *a_data = (guint16 *) avifImagePlane (decoder->image, AVIF_CHAN_A);
|
||||
guint16 *dst_data = (guint16 *) data;
|
||||
gsize y_stride = avifImagePlaneRowBytes (decoder->image, AVIF_CHAN_Y) / 2;
|
||||
gsize u_stride = avifImagePlaneRowBytes (decoder->image, AVIF_CHAN_U) / 2;
|
||||
gsize v_stride = avifImagePlaneRowBytes (decoder->image, AVIF_CHAN_V) / 2;
|
||||
gsize a_stride = avifImagePlaneRowBytes (decoder->image, AVIF_CHAN_A) / 2;
|
||||
gsize dst_stride = stride / 2;
|
||||
|
||||
for (int y = 0; y < height; y += Y_SUB)
|
||||
{
|
||||
for (int x = 0; x < width; x += X_SUB)
|
||||
{
|
||||
guint y_, u_, v_, a_;
|
||||
|
||||
u_ = u_data[x / X_SUB] << (16 - depth);
|
||||
v_ = v_data[x / X_SUB] << (16 - depth);
|
||||
|
||||
for (int ys = 0; ys < Y_SUB && y + ys < height; ys++)
|
||||
for (int xs = 0; xs < X_SUB && x + xs < width; xs++)
|
||||
{
|
||||
guint16 *dest = &dst_data[4 * (x + xs) + dst_stride * ys];
|
||||
|
||||
y_ = y_data[x + xs + y_stride * ys] << (16 - depth);
|
||||
a_ = (a_data ? a_data[x + xs + a_stride * ys] : 0xffff) << (16 - depth);
|
||||
|
||||
dest[0] = y_ | (y_ >> depth);
|
||||
dest[1] = u_ | (u_ >> depth);
|
||||
dest[2] = v_ | (v_ >> depth);
|
||||
dest[3] = a_ | (a_ >> depth);
|
||||
}
|
||||
}
|
||||
|
||||
dst_data += Y_SUB * dst_stride;
|
||||
y_data += Y_SUB * y_stride;
|
||||
u_data += u_stride;
|
||||
v_data += v_stride;
|
||||
}
|
||||
}
|
||||
|
||||
builder = gdk_memory_texture_builder_new ();
|
||||
|
||||
bytes = g_bytes_new_take (data, stride * height);
|
||||
|
||||
gdk_memory_texture_builder_set_width (builder, width);
|
||||
gdk_memory_texture_builder_set_height (builder, height);
|
||||
gdk_memory_texture_builder_set_bytes (builder, bytes);
|
||||
gdk_memory_texture_builder_set_stride (builder, stride);
|
||||
gdk_memory_texture_builder_set_format (builder, format);
|
||||
gdk_memory_texture_builder_set_color_state (builder, color_state);
|
||||
|
||||
texture = gdk_memory_texture_builder_build (builder);
|
||||
|
||||
g_bytes_unref (bytes);
|
||||
g_object_unref (builder);
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
/* }}} */
|
||||
/* {{{ Public API */
|
||||
|
||||
GdkTexture *
|
||||
gdk_load_avif (GBytes *bytes,
|
||||
GError **error)
|
||||
{
|
||||
avifDecoder *decoder;
|
||||
avifResult result;
|
||||
GdkCicpParams *params;
|
||||
GdkColorState *color_state = NULL;
|
||||
GdkTexture *texture = NULL;
|
||||
GError *local_error = NULL;
|
||||
|
||||
decoder = avifDecoderCreate ();
|
||||
result = avifDecoderSetIOMemory (decoder,
|
||||
g_bytes_get_data (bytes, NULL),
|
||||
g_bytes_get_size (bytes));
|
||||
if (result != AVIF_RESULT_OK)
|
||||
{
|
||||
g_set_error (error,
|
||||
GDK_TEXTURE_ERROR, GDK_TEXTURE_ERROR_UNSUPPORTED_CONTENT,
|
||||
"avifDecoderSetIOFile failed: %u", result);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
result = avifDecoderParse (decoder);
|
||||
if (result != AVIF_RESULT_OK)
|
||||
{
|
||||
g_set_error (error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_FAILED,
|
||||
"avifDecoderParse failed: %u", result);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
result = avifDecoderNextImage (decoder);
|
||||
if (result != AVIF_RESULT_OK)
|
||||
{
|
||||
g_set_error (error,
|
||||
GDK_TEXTURE_ERROR, GDK_TEXTURE_ERROR_UNSUPPORTED_CONTENT,
|
||||
"avifDecoderNextImage failed: %u", result);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
DEBUG ("load: depth %u", decoder->image->depth);
|
||||
|
||||
DEBUG ("load: cicp %u/%u/%u/%u",
|
||||
decoder->image->colorPrimaries,
|
||||
decoder->image->transferCharacteristics,
|
||||
decoder->image->matrixCoefficients,
|
||||
decoder->image->yuvRange);
|
||||
|
||||
params = gdk_cicp_params_new ();
|
||||
gdk_cicp_params_set_color_primaries (params, decoder->image->colorPrimaries);
|
||||
gdk_cicp_params_set_transfer_function (params, decoder->image->transferCharacteristics);
|
||||
gdk_cicp_params_set_matrix_coefficients (params, decoder->image->matrixCoefficients);
|
||||
gdk_cicp_params_set_range (params, decoder->image->yuvRange == AVIF_RANGE_LIMITED
|
||||
? GDK_CICP_RANGE_NARROW
|
||||
: GDK_CICP_RANGE_FULL);
|
||||
|
||||
color_state = gdk_cicp_params_build_color_state (params, error);
|
||||
g_object_unref (params);
|
||||
|
||||
if (!color_state)
|
||||
goto fail;
|
||||
|
||||
#ifdef HAVE_DMABUF
|
||||
texture = gdk_avif_create_dmabuf_texture (decoder, color_state, &local_error);
|
||||
|
||||
if (!texture)
|
||||
{
|
||||
DEBUG ("load: creating dmabuf failed: %s", local_error->message);
|
||||
g_clear_error (&local_error);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!texture)
|
||||
texture = gdk_avif_create_memory_texture (decoder, color_state, error);
|
||||
|
||||
(gdk_color_state_unref) (color_state);
|
||||
|
||||
fail:
|
||||
avifDecoderDestroy (decoder);
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
static int
|
||||
bytes_per_channel (GdkMemoryFormat format)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case GDK_MEMORY_B8G8R8A8_PREMULTIPLIED:
|
||||
case GDK_MEMORY_A8R8G8B8_PREMULTIPLIED:
|
||||
case GDK_MEMORY_R8G8B8A8_PREMULTIPLIED:
|
||||
case GDK_MEMORY_B8G8R8A8:
|
||||
case GDK_MEMORY_A8R8G8B8:
|
||||
case GDK_MEMORY_R8G8B8A8:
|
||||
case GDK_MEMORY_A8B8G8R8:
|
||||
case GDK_MEMORY_R8G8B8:
|
||||
case GDK_MEMORY_B8G8R8:
|
||||
case GDK_MEMORY_G8A8_PREMULTIPLIED:
|
||||
case GDK_MEMORY_G8A8:
|
||||
case GDK_MEMORY_G8:
|
||||
case GDK_MEMORY_A8:
|
||||
case GDK_MEMORY_A8B8G8R8_PREMULTIPLIED:
|
||||
case GDK_MEMORY_B8G8R8X8:
|
||||
case GDK_MEMORY_X8R8G8B8:
|
||||
case GDK_MEMORY_R8G8B8X8:
|
||||
case GDK_MEMORY_X8B8G8R8:
|
||||
return 1;
|
||||
case GDK_MEMORY_R16G16B16:
|
||||
case GDK_MEMORY_R16G16B16A16_PREMULTIPLIED:
|
||||
case GDK_MEMORY_R16G16B16A16:
|
||||
case GDK_MEMORY_R16G16B16_FLOAT:
|
||||
case GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED:
|
||||
case GDK_MEMORY_R16G16B16A16_FLOAT:
|
||||
case GDK_MEMORY_G16A16_PREMULTIPLIED:
|
||||
case GDK_MEMORY_G16A16:
|
||||
case GDK_MEMORY_G16:
|
||||
case GDK_MEMORY_A16:
|
||||
case GDK_MEMORY_A16_FLOAT:
|
||||
return 2;
|
||||
case GDK_MEMORY_R32G32B32_FLOAT:
|
||||
case GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED:
|
||||
case GDK_MEMORY_R32G32B32A32_FLOAT:
|
||||
case GDK_MEMORY_A32_FLOAT:
|
||||
return 4;
|
||||
case GDK_MEMORY_N_FORMATS:
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
}
|
||||
|
||||
GBytes *
|
||||
gdk_save_avif (GdkTexture *texture)
|
||||
{
|
||||
uint32_t width, height, depth;
|
||||
GdkColorState *color_state;
|
||||
const GdkCicp *cicp;
|
||||
avifEncoder *encoder;
|
||||
avifImage *image = NULL;
|
||||
avifRWData output = AVIF_DATA_EMPTY;
|
||||
GdkTextureDownloader *downloader;
|
||||
GBytes *bytes = NULL;
|
||||
gsize stride;
|
||||
GBytes *out_bytes = NULL;
|
||||
|
||||
width = gdk_texture_get_width (texture);
|
||||
height = gdk_texture_get_height (texture);
|
||||
|
||||
if (bytes_per_channel (gdk_texture_get_format (texture)) == 1)
|
||||
depth = 8;
|
||||
else
|
||||
depth = 12;
|
||||
|
||||
color_state = gdk_texture_get_color_state (texture);
|
||||
cicp = gdk_color_state_get_cicp (color_state);
|
||||
|
||||
DEBUG ("save: depth %u", depth);
|
||||
|
||||
DEBUG ("save: cicp %u/%u/%u/%u",
|
||||
cicp->color_primaries,
|
||||
cicp->transfer_function,
|
||||
cicp->matrix_coefficients,
|
||||
cicp->range);
|
||||
|
||||
downloader = gdk_texture_downloader_new (texture);
|
||||
if (depth == 8)
|
||||
gdk_texture_downloader_set_format (downloader, GDK_MEMORY_R8G8B8A8);
|
||||
else
|
||||
gdk_texture_downloader_set_format (downloader, GDK_MEMORY_R16G16B16A16);
|
||||
gdk_texture_downloader_set_color_state (downloader, gdk_texture_get_color_state (texture));
|
||||
|
||||
bytes = gdk_texture_downloader_download_bytes (downloader, &stride);
|
||||
gdk_texture_downloader_free (downloader);
|
||||
|
||||
if (cicp->matrix_coefficients != 0)
|
||||
{
|
||||
/* some form of yuv */
|
||||
image = avifImageCreate (width, height, depth, AVIF_PIXEL_FORMAT_YUV444);
|
||||
image->colorPrimaries = cicp->color_primaries;
|
||||
image->transferCharacteristics = cicp->transfer_function;
|
||||
image->matrixCoefficients = cicp->matrix_coefficients;
|
||||
image->yuvRange = cicp->range == GDK_CICP_RANGE_NARROW
|
||||
? AVIF_RANGE_LIMITED
|
||||
: AVIF_RANGE_FULL;
|
||||
|
||||
avifImageAllocatePlanes (image, AVIF_PLANES_YUV);
|
||||
|
||||
if (depth == 8)
|
||||
{
|
||||
for (gsize y = 0; y < height; y++)
|
||||
{
|
||||
const guchar *orig = (guchar *) g_bytes_get_data (bytes, NULL) + y * stride;
|
||||
guchar *y_ = avifImagePlane (image, AVIF_CHAN_Y) + y * avifImagePlaneRowBytes (image, AVIF_CHAN_Y);
|
||||
guchar *u_ = avifImagePlane (image, AVIF_CHAN_U) + y * avifImagePlaneRowBytes (image, AVIF_CHAN_U);
|
||||
guchar *v_ = avifImagePlane (image, AVIF_CHAN_V) + y * avifImagePlaneRowBytes (image, AVIF_CHAN_V);
|
||||
|
||||
for (gsize x = 0; x < width; x++)
|
||||
{
|
||||
y_[x] = orig[4*x + 0];
|
||||
u_[x] = orig[4*x + 1];
|
||||
v_[x] = orig[4*x + 2];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (gsize y = 0; y < height; y++)
|
||||
{
|
||||
const guint16 *orig = (guint16 *) ((guchar *) g_bytes_get_data (bytes, NULL) + y * stride);
|
||||
guint16 *y_ = (guint16 *) (avifImagePlane (image, AVIF_CHAN_Y) + y * avifImagePlaneRowBytes (image, AVIF_CHAN_Y));
|
||||
guint16 *u_ = (guint16 *) (avifImagePlane (image, AVIF_CHAN_U) + y * avifImagePlaneRowBytes (image, AVIF_CHAN_U));
|
||||
guint16 *v_ = (guint16 *) (avifImagePlane (image, AVIF_CHAN_V) + y * avifImagePlaneRowBytes (image, AVIF_CHAN_V));
|
||||
|
||||
for (gsize x = 0; x < width; x++)
|
||||
{
|
||||
y_[x] = orig[4*x + 0] >> (16 - depth);
|
||||
u_[x] = orig[4*x + 1] >> (16 - depth);
|
||||
v_[x] = orig[4*x + 2] >> (16 - depth);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
avifRGBImage rgb;
|
||||
|
||||
image = avifImageCreate (width, height, depth, AVIF_PIXEL_FORMAT_YUV444);
|
||||
image->colorPrimaries = cicp->color_primaries;
|
||||
image->transferCharacteristics = cicp->transfer_function;
|
||||
image->matrixCoefficients = cicp->matrix_coefficients;
|
||||
image->yuvRange = cicp->range == GDK_CICP_RANGE_NARROW
|
||||
? AVIF_RANGE_LIMITED
|
||||
: AVIF_RANGE_FULL;
|
||||
|
||||
avifRGBImageSetDefaults (&rgb, image);
|
||||
avifRGBImageAllocatePixels (&rgb);
|
||||
|
||||
if (depth == 8)
|
||||
{
|
||||
for (gsize y = 0; y < height; y++)
|
||||
{
|
||||
const guchar *orig = (guchar *) g_bytes_get_data (bytes, NULL) + y * stride;
|
||||
guchar *pixels = rgb.pixels + y * rgb.rowBytes;
|
||||
for (gsize x = 0; x < width; x++)
|
||||
{
|
||||
pixels[4*x + 0] = orig[4*x + 0];
|
||||
pixels[4*x + 1] = orig[4*x + 1];
|
||||
pixels[4*x + 2] = orig[4*x + 2];
|
||||
pixels[4*x + 3] = orig[4*x + 3];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (gsize y = 0; y < height; y++)
|
||||
{
|
||||
const guint16 *orig = (const guint16 *) ((guchar *) g_bytes_get_data (bytes, NULL) + y * stride);
|
||||
guint16 *pixels = (guint16 *) (rgb.pixels + y * rgb.rowBytes);
|
||||
for (gsize x = 0; x < width; x++)
|
||||
{
|
||||
pixels[4*x + 0] = orig[4*x + 0] >> (16 - depth);
|
||||
pixels[4*x + 1] = orig[4*x + 1] >> (16 - depth);
|
||||
pixels[4*x + 2] = orig[4*x + 2] >> (16 - depth);
|
||||
pixels[4*x + 3] = orig[4*x + 3] >> (16 - depth);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
avifImageRGBToYUV(image, &rgb);
|
||||
avifRGBImageFreePixels (&rgb);
|
||||
}
|
||||
|
||||
DEBUG ("save: cicp in image %u/%u/%u/%u",
|
||||
image->colorPrimaries,
|
||||
image->transferCharacteristics,
|
||||
image->matrixCoefficients,
|
||||
image->yuvRange);
|
||||
|
||||
encoder = avifEncoderCreate ();
|
||||
|
||||
if (avifEncoderWrite (encoder, image, &output) != AVIF_RESULT_OK)
|
||||
goto fail;
|
||||
|
||||
out_bytes = g_bytes_new_take (output.data, output.size);
|
||||
|
||||
fail:
|
||||
g_clear_pointer (&bytes, g_bytes_unref);
|
||||
avifEncoderDestroy (encoder);
|
||||
if (image)
|
||||
avifImageDestroy (image);
|
||||
|
||||
return out_bytes;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gdk_is_avif (GBytes *bytes)
|
||||
{
|
||||
avifROData input;
|
||||
|
||||
input.data = g_bytes_get_data (bytes, &input.size);
|
||||
|
||||
return avifPeekCompatibleFileType (&input);
|
||||
}
|
||||
|
||||
/* }}} */
|
||||
|
||||
/* vim:set foldmethod=marker expandtab: */
|
28
gdk/loaders/gdkavifprivate.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/* GDK - The GIMP Drawing Kit
|
||||
* Copyright (C) 2024 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/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gdk.h>
|
||||
#include <gio/gio.h>
|
||||
|
||||
GdkTexture *gdk_load_avif (GBytes *bytes,
|
||||
GError **error);
|
||||
|
||||
GBytes *gdk_save_avif (GdkTexture *texture);
|
||||
|
||||
gboolean gdk_is_avif (GBytes *bytes);
|
@@ -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);
|
||||
|
@@ -74,6 +74,12 @@ gdk_public_sources = files([
|
||||
'loaders/gdkjpeg.c',
|
||||
])
|
||||
|
||||
if avif_dep.found()
|
||||
gdk_public_sources += [
|
||||
'loaders/gdkavif.c'
|
||||
]
|
||||
endif
|
||||
|
||||
gdk_public_headers = files([
|
||||
'gdk.h',
|
||||
'gdkapplaunchcontext.h',
|
||||
@@ -237,6 +243,7 @@ gdk_deps = [
|
||||
png_dep,
|
||||
tiff_dep,
|
||||
jpeg_dep,
|
||||
avif_dep,
|
||||
]
|
||||
|
||||
if profiler_enabled
|
||||
|
@@ -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>
|
||||
@@ -814,6 +815,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);
|
||||
|
||||
@@ -831,10 +834,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;
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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)
|
||||
|
||||
|
@@ -1860,7 +1860,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));
|
||||
@@ -1868,7 +1867,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;
|
||||
}
|
||||
|
||||
@@ -1878,17 +1877,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;
|
||||
}
|
||||
|
||||
@@ -1922,7 +1918,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;
|
||||
@@ -1949,6 +1944,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,
|
||||
@@ -1977,13 +1974,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);
|
||||
}
|
||||
|
||||
@@ -1991,7 +1983,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))
|
||||
@@ -2004,6 +1997,7 @@ gsk_gpu_node_processor_draw_texture_tiles (GskGpuNodeProcessor *self,
|
||||
&tile_rect,
|
||||
&tile_rect);
|
||||
|
||||
gdk_color_state_unref (tile_cs);
|
||||
g_object_unref (tile);
|
||||
}
|
||||
}
|
||||
@@ -2092,7 +2086,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,
|
||||
@@ -2119,6 +2114,7 @@ gsk_gpu_node_processor_add_texture_node (GskGpuNodeProcessor *self,
|
||||
&node->bounds);
|
||||
}
|
||||
|
||||
gdk_color_state_unref (image_cs);
|
||||
g_object_unref (image);
|
||||
}
|
||||
|
||||
@@ -2165,6 +2161,7 @@ gsk_gpu_get_texture_node_as_image (GskGpuFrame *frame,
|
||||
}
|
||||
|
||||
*out_bounds = node->bounds;
|
||||
gdk_color_state_unref (image_cs);
|
||||
return image;
|
||||
}
|
||||
|
||||
@@ -2203,6 +2200,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;
|
||||
}
|
||||
@@ -2245,7 +2243,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,
|
||||
@@ -2265,6 +2264,7 @@ gsk_gpu_node_processor_add_texture_scale_node (GskGpuNodeProcessor *self,
|
||||
&node->bounds,
|
||||
});
|
||||
|
||||
gdk_color_state_unref (image_cs);
|
||||
g_object_unref (image);
|
||||
}
|
||||
|
||||
|
@@ -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,
|
||||
|
@@ -188,6 +188,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);
|
||||
|
||||
@@ -210,6 +211,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)
|
||||
|
@@ -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);
|
||||
|
@@ -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);
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -41,6 +41,7 @@
|
||||
#include "gtk/css/gtkcssdataurlprivate.h"
|
||||
#include "gtk/css/gtkcssparserprivate.h"
|
||||
#include "gtk/css/gtkcssserializerprivate.h"
|
||||
#include "gdk/loaders/gdkavifprivate.h"
|
||||
|
||||
#ifdef CAIRO_HAS_SCRIPT_SURFACE
|
||||
#include <cairo-script.h>
|
||||
@@ -216,11 +217,19 @@ parse_texture (GtkCssParser *parser,
|
||||
if (scheme && g_ascii_strcasecmp (scheme, "data") == 0)
|
||||
{
|
||||
GBytes *bytes;
|
||||
char *mimetype;
|
||||
|
||||
bytes = gtk_css_data_url_parse (url, NULL, &error);
|
||||
bytes = gtk_css_data_url_parse (url, &mimetype, &error);
|
||||
if (bytes)
|
||||
{
|
||||
texture = gdk_texture_new_from_bytes (bytes, &error);
|
||||
#ifdef HAVE_AVIF
|
||||
if (strcmp (mimetype, "image/avif") == 0)
|
||||
texture = gdk_load_avif (bytes, &error);
|
||||
else
|
||||
#endif
|
||||
texture = gdk_texture_new_from_bytes (bytes, &error);
|
||||
|
||||
g_free (mimetype);
|
||||
g_bytes_unref (bytes);
|
||||
}
|
||||
else
|
||||
@@ -3922,12 +3931,27 @@ base64_encode_with_linebreaks (const guchar *data,
|
||||
return out;
|
||||
}
|
||||
|
||||
#ifdef HAVE_AVIF
|
||||
static gboolean
|
||||
texture_should_use_avif (GdkTexture *texture)
|
||||
{
|
||||
GdkColorState *color_state;
|
||||
const GdkCicp *cicp;
|
||||
|
||||
color_state = gdk_texture_get_color_state (texture);
|
||||
cicp = gdk_color_state_get_cicp (color_state);
|
||||
|
||||
return cicp->matrix_coefficients != 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
append_texture_param (Printer *p,
|
||||
const char *param_name,
|
||||
GdkTexture *texture)
|
||||
{
|
||||
GBytes *bytes;
|
||||
const char *mimetype;
|
||||
char *b64;
|
||||
const char *texture_name;
|
||||
|
||||
@@ -3956,26 +3980,38 @@ append_texture_param (Printer *p,
|
||||
g_hash_table_insert (p->named_textures, texture, new_name);
|
||||
}
|
||||
|
||||
switch (gdk_texture_get_depth (texture))
|
||||
#ifdef HAVE_AVIF
|
||||
if (texture_should_use_avif (texture))
|
||||
{
|
||||
case GDK_MEMORY_U8:
|
||||
case GDK_MEMORY_U8_SRGB:
|
||||
case GDK_MEMORY_U16:
|
||||
bytes = gdk_texture_save_to_png_bytes (texture);
|
||||
g_string_append (p->str, "url(\"data:image/png;base64,\\\n");
|
||||
break;
|
||||
|
||||
case GDK_MEMORY_FLOAT16:
|
||||
case GDK_MEMORY_FLOAT32:
|
||||
bytes = gdk_texture_save_to_tiff_bytes (texture);
|
||||
g_string_append (p->str, "url(\"data:image/tiff;base64,\\\n");
|
||||
break;
|
||||
|
||||
case GDK_MEMORY_NONE:
|
||||
case GDK_N_DEPTHS:
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
bytes = gdk_save_avif (texture);
|
||||
mimetype = "image/avif";
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
switch (gdk_texture_get_depth (texture))
|
||||
{
|
||||
case GDK_MEMORY_U8:
|
||||
case GDK_MEMORY_U8_SRGB:
|
||||
case GDK_MEMORY_U16:
|
||||
bytes = gdk_texture_save_to_png_bytes (texture);
|
||||
mimetype = "image/png";
|
||||
break;
|
||||
|
||||
case GDK_MEMORY_FLOAT16:
|
||||
case GDK_MEMORY_FLOAT32:
|
||||
bytes = gdk_texture_save_to_tiff_bytes (texture);
|
||||
mimetype = "image/tiff";
|
||||
break;
|
||||
|
||||
case GDK_MEMORY_NONE:
|
||||
case GDK_N_DEPTHS:
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
}
|
||||
|
||||
g_string_append_printf (p->str, "url(\"data:%s;base64,\\\n", mimetype);
|
||||
|
||||
b64 = base64_encode_with_linebreaks (g_bytes_get_data (bytes, NULL),
|
||||
g_bytes_get_size (bytes));
|
||||
|
@@ -417,6 +417,9 @@ pixbuf_dep = dependency('gdk-pixbuf-2.0', version: gdk_pixbuf_req,
|
||||
png_dep = dependency('libpng', 'png')
|
||||
tiff_dep = dependency('libtiff-4', 'tiff')
|
||||
jpeg_dep = dependency('libjpeg', 'jpeg')
|
||||
avif_dep = dependency('libavif', required: get_option('avif'))
|
||||
|
||||
cdata.set('HAVE_AVIF', avif_dep.found())
|
||||
|
||||
epoxy_dep = dependency('epoxy', version: epoxy_req)
|
||||
xkbdep = dependency('xkbcommon', version: xkbcommon_req, required: wayland_enabled)
|
||||
@@ -955,6 +958,7 @@ summary('Cloud support', cloudproviders_dep.found(), section: 'Features')
|
||||
summary('Sysprof support', libsysprof_capture_dep.found(), section: 'Features')
|
||||
summary('Colord support', colord_dep.found(), section: 'Features')
|
||||
summary('Tracker support', tracker3_dep.found(), section: 'Features')
|
||||
summary('AVIF support', avif_dep.found(), section: 'Features')
|
||||
|
||||
summary('Compiler', cc.get_id(), section: 'Toolchain')
|
||||
summary('Linker', cc.get_linker_id(), section: 'Toolchain')
|
||||
|
@@ -52,6 +52,11 @@ option('print-cups',
|
||||
|
||||
# Optional features
|
||||
|
||||
option('avif',
|
||||
type: 'feature',
|
||||
value: 'disabled',
|
||||
description: 'Enable support for AVIF images, for GTK development')
|
||||
|
||||
option('vulkan',
|
||||
type: 'feature',
|
||||
value: 'enabled',
|
||||
|
@@ -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>
|
||||
@@ -156,9 +158,72 @@ add_drm_formats_and_modifiers (GstCaps *caps,
|
||||
&dmabuf_list);
|
||||
}
|
||||
|
||||
#ifdef HAVE_GSTREAMER_DRM
|
||||
static inline gboolean
|
||||
dmabuf_fourcc_is_yuv (guint32 fourcc)
|
||||
{
|
||||
switch (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:
|
||||
return TRUE;
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static GdkColorState *
|
||||
gtk_gst_color_state_from_colorimetry (GtkGstSink *self,
|
||||
const GstVideoColorimetry *colorimetry)
|
||||
const GstVideoColorimetry *colorimetry,
|
||||
gconstpointer drm)
|
||||
{
|
||||
GdkCicpParams *params;
|
||||
GdkColorState *color_state;
|
||||
@@ -176,18 +241,40 @@ 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)
|
||||
{
|
||||
if (dmabuf_fourcc_is_yuv (drm_info->drm_fourcc))
|
||||
{
|
||||
GST_DEBUG_OBJECT (self, "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);
|
||||
}
|
||||
}
|
||||
#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);
|
||||
GST_DEBUG_OBJECT (self, "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);
|
||||
|
||||
GST_DEBUG_OBJECT (self, "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)
|
||||
@@ -266,7 +353,14 @@ gtk_gst_sink_set_caps (GstBaseSink *bsink,
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
|
@@ -49,6 +49,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
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -6,6 +6,12 @@ clipboard_client = executable('clipboard-client',
|
||||
install: false,
|
||||
)
|
||||
|
||||
extra_yuv_sources = []
|
||||
|
||||
if avif_dep.found()
|
||||
extra_yuv_sources += ['../../gdk/loaders/gdkavif.c']
|
||||
endif
|
||||
|
||||
tests = [
|
||||
{ 'name': 'array' },
|
||||
{ 'name': 'cairo' },
|
||||
@@ -24,8 +30,12 @@ tests = [
|
||||
{ 'name': 'texture-threads' },
|
||||
{ 'name': 'toplevellayout' },
|
||||
{ 'name': 'popuplayout' },
|
||||
{ 'name': 'yuv',
|
||||
'sources': [ 'yuv.c', '../reftests/reftest-compare.c' ] + extra_yuv_sources,
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
if x11_enabled
|
||||
tests += [
|
||||
{ 'name': 'display' },
|
||||
@@ -36,7 +46,7 @@ endif
|
||||
foreach t : tests
|
||||
test_name = t.get('name')
|
||||
test_exe = executable(test_name,
|
||||
sources: '@0@.c'.format(test_name),
|
||||
sources: ['@0@.c'.format(test_name)] + t.get('sources', []),
|
||||
c_args: common_cflags,
|
||||
dependencies: libgtk_dep,
|
||||
install: false,
|
||||
@@ -76,7 +86,7 @@ endif
|
||||
foreach t : internal_tests
|
||||
test_name = t.get('name')
|
||||
test_exe = executable(test_name,
|
||||
sources: '@0@.c'.format(test_name),
|
||||
sources: ['@0@.c'.format(test_name)] + t.get('sources', []),
|
||||
c_args: common_cflags + ['-DGTK_COMPILATION'],
|
||||
dependencies: libgtk_static_dep,
|
||||
install: false,
|
||||
|
BIN
testsuite/gdk/yuv-images/blue-d10-y420-rf.avif
Normal file
After Width: | Height: | Size: 999 B |
BIN
testsuite/gdk/yuv-images/blue-d10-y420-rl.avif
Normal file
After Width: | Height: | Size: 999 B |
BIN
testsuite/gdk/yuv-images/blue-d10-y422-rf.avif
Normal file
After Width: | Height: | Size: 996 B |
BIN
testsuite/gdk/yuv-images/blue-d10-y422-rl.avif
Normal file
After Width: | Height: | Size: 996 B |
BIN
testsuite/gdk/yuv-images/blue-d10-y444-rf.avif
Normal file
After Width: | Height: | Size: 1000 B |
BIN
testsuite/gdk/yuv-images/blue-d10-y444-rl.avif
Normal file
After Width: | Height: | Size: 1000 B |
BIN
testsuite/gdk/yuv-images/blue-d12-y420-rf.avif
Normal file
After Width: | Height: | Size: 997 B |
BIN
testsuite/gdk/yuv-images/blue-d12-y420-rl.avif
Normal file
After Width: | Height: | Size: 997 B |
BIN
testsuite/gdk/yuv-images/blue-d12-y422-rf.avif
Normal file
After Width: | Height: | Size: 998 B |
BIN
testsuite/gdk/yuv-images/blue-d12-y422-rl.avif
Normal file
After Width: | Height: | Size: 998 B |
BIN
testsuite/gdk/yuv-images/blue-d12-y444-rf.avif
Normal file
After Width: | Height: | Size: 998 B |
BIN
testsuite/gdk/yuv-images/blue-d12-y444-rl.avif
Normal file
After Width: | Height: | Size: 998 B |
BIN
testsuite/gdk/yuv-images/blue-d8-y420-rf.avif
Normal file
After Width: | Height: | Size: 998 B |
BIN
testsuite/gdk/yuv-images/blue-d8-y420-rl.avif
Normal file
After Width: | Height: | Size: 998 B |
BIN
testsuite/gdk/yuv-images/blue-d8-y422-rf.avif
Normal file
After Width: | Height: | Size: 995 B |
BIN
testsuite/gdk/yuv-images/blue-d8-y422-rl.avif
Normal file
After Width: | Height: | Size: 995 B |
BIN
testsuite/gdk/yuv-images/blue-d8-y444-rf.avif
Normal file
After Width: | Height: | Size: 998 B |
BIN
testsuite/gdk/yuv-images/blue-d8-y444-rl.avif
Normal file
After Width: | Height: | Size: 998 B |
BIN
testsuite/gdk/yuv-images/blue.png
Normal file
After Width: | Height: | Size: 550 B |
BIN
testsuite/gdk/yuv-images/orange-d10-y420-rf.avif
Normal file
After Width: | Height: | Size: 318 B |
BIN
testsuite/gdk/yuv-images/orange-d10-y420-rl.avif
Normal file
After Width: | Height: | Size: 318 B |
BIN
testsuite/gdk/yuv-images/orange-d10-y422-rf.avif
Normal file
After Width: | Height: | Size: 315 B |
BIN
testsuite/gdk/yuv-images/orange-d10-y422-rl.avif
Normal file
After Width: | Height: | Size: 315 B |
BIN
testsuite/gdk/yuv-images/orange-d10-y444-rf.avif
Normal file
After Width: | Height: | Size: 318 B |
BIN
testsuite/gdk/yuv-images/orange-d10-y444-rl.avif
Normal file
After Width: | Height: | Size: 318 B |
BIN
testsuite/gdk/yuv-images/orange-d12-y420-rf.avif
Normal file
After Width: | Height: | Size: 316 B |
BIN
testsuite/gdk/yuv-images/orange-d12-y420-rl.avif
Normal file
After Width: | Height: | Size: 316 B |
BIN
testsuite/gdk/yuv-images/orange-d12-y422-rf.avif
Normal file
After Width: | Height: | Size: 316 B |
BIN
testsuite/gdk/yuv-images/orange-d12-y422-rl.avif
Normal file
After Width: | Height: | Size: 316 B |
BIN
testsuite/gdk/yuv-images/orange-d12-y444-rf.avif
Normal file
After Width: | Height: | Size: 317 B |
BIN
testsuite/gdk/yuv-images/orange-d12-y444-rl.avif
Normal file
After Width: | Height: | Size: 317 B |
BIN
testsuite/gdk/yuv-images/orange-d8-y420-rf.avif
Normal file
After Width: | Height: | Size: 317 B |
BIN
testsuite/gdk/yuv-images/orange-d8-y420-rl.avif
Normal file
After Width: | Height: | Size: 316 B |
BIN
testsuite/gdk/yuv-images/orange-d8-y422-rf.avif
Normal file
After Width: | Height: | Size: 313 B |
BIN
testsuite/gdk/yuv-images/orange-d8-y422-rl.avif
Normal file
After Width: | Height: | Size: 313 B |
BIN
testsuite/gdk/yuv-images/orange-d8-y444-rf.avif
Normal file
After Width: | Height: | Size: 317 B |
BIN
testsuite/gdk/yuv-images/orange-d8-y444-rl.avif
Normal file
After Width: | Height: | Size: 316 B |
BIN
testsuite/gdk/yuv-images/orange.png
Normal file
After Width: | Height: | Size: 100 B |
236
testsuite/gdk/yuv.c
Normal file
@@ -0,0 +1,236 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include "gdk/loaders/gdkavifprivate.h"
|
||||
|
||||
#include "../reftests/reftest-compare.h"
|
||||
|
||||
|
||||
static float
|
||||
image_distance (const guchar *data,
|
||||
gsize stride,
|
||||
const guchar *data2,
|
||||
gsize stride2,
|
||||
gsize width,
|
||||
gsize height)
|
||||
{
|
||||
float dist = 0;
|
||||
gsize imax = 0, jmax = 0;
|
||||
float r1 = 0, g1 = 0, b1 = 0, a1 = 0;
|
||||
float r2 = 0, g2 = 0, b2 = 0, a2 = 0;
|
||||
|
||||
for (gsize i = 0; i < height; i++)
|
||||
{
|
||||
const float *p = (const float *) (data + i * stride);
|
||||
const float *p2 = (const float *) (data2 + i * stride2);
|
||||
|
||||
for (gsize j = 0; j < width; j++)
|
||||
{
|
||||
float dr, dg, db, da;
|
||||
|
||||
dr = p[4 * j + 0] - p2[4 * j + 0];
|
||||
dg = p[4 * j + 1] - p2[4 * j + 1];
|
||||
db = p[4 * j + 2] - p2[4 * j + 2];
|
||||
da = p[4 * j + 3] - p2[4 * j + 3];
|
||||
|
||||
float d = dr * dr + dg * dg + db * db + da * da;
|
||||
if (d > dist)
|
||||
{
|
||||
dist = d;
|
||||
imax = i;
|
||||
jmax = j;
|
||||
r1 = p[4 * j + 0];
|
||||
g1 = p[4 * j + 1];
|
||||
b1 = p[4 * j + 2];
|
||||
a1 = p[4 * j + 3];
|
||||
r2 = p2[4 * j + 0];
|
||||
g2 = p2[4 * j + 1];
|
||||
b2 = p2[4 * j + 2];
|
||||
a2 = p2[4 * j + 3];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (g_test_verbose() &&
|
||||
dist > 0)
|
||||
{
|
||||
g_print ("worst pixel %" G_GSIZE_FORMAT " %" G_GSIZE_FORMAT ": %f %f %f %f vs %f %f %f %f %f\n",
|
||||
imax, jmax, r1, g1, b1, a1, r2, g2, b2, a2, sqrt (dist));
|
||||
}
|
||||
|
||||
return sqrt (dist);
|
||||
}
|
||||
|
||||
static void
|
||||
assert_texture_equal (GdkTexture *t1,
|
||||
GdkTexture *t2)
|
||||
{
|
||||
int width;
|
||||
int height;
|
||||
int stride;
|
||||
guchar *d1;
|
||||
guchar *d2;
|
||||
GdkTextureDownloader *downloader;
|
||||
|
||||
width = gdk_texture_get_width (t1);
|
||||
height = gdk_texture_get_height (t1);
|
||||
|
||||
g_assert_cmpint (width, ==, gdk_texture_get_width (t2));
|
||||
g_assert_cmpint (height, ==, gdk_texture_get_height (t2));
|
||||
|
||||
stride = 4 * width * sizeof (float);
|
||||
d1 = g_malloc (stride * height);
|
||||
d2 = g_malloc (stride * height);
|
||||
|
||||
downloader = gdk_texture_downloader_new (t1);
|
||||
gdk_texture_downloader_set_format (downloader, GDK_MEMORY_R32G32B32A32_FLOAT);
|
||||
gdk_texture_downloader_set_color_state (downloader, gdk_color_state_get_srgb ());
|
||||
|
||||
gdk_texture_downloader_download_into (downloader, d1, stride);
|
||||
|
||||
gdk_texture_downloader_free (downloader);
|
||||
|
||||
downloader = gdk_texture_downloader_new (t2);
|
||||
gdk_texture_downloader_set_format (downloader, GDK_MEMORY_R32G32B32A32_FLOAT);
|
||||
gdk_texture_downloader_set_color_state (downloader, gdk_color_state_get_srgb ());
|
||||
|
||||
gdk_texture_downloader_download_into (downloader, d2, stride);
|
||||
|
||||
gdk_texture_downloader_free (downloader);
|
||||
|
||||
#if 0
|
||||
GdkTexture *diff;
|
||||
diff = reftest_compare_textures (t1, t2);
|
||||
if (diff)
|
||||
{
|
||||
gdk_texture_save_to_png (t1, "pattern1.png");
|
||||
gdk_texture_save_to_png (t2, "pattern2.png");
|
||||
gdk_texture_save_to_png (diff, "pattern.diff.png");
|
||||
g_object_unref (diff);
|
||||
g_test_fail ();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (image_distance (d1, stride, d2, stride, width, height) > 0.01)
|
||||
{
|
||||
g_test_fail ();
|
||||
return;
|
||||
}
|
||||
|
||||
//g_assert_cmpmem (d1, stride * height, d2, stride * height);
|
||||
|
||||
g_free (d1);
|
||||
g_free (d2);
|
||||
}
|
||||
|
||||
static char *
|
||||
get_reference (const char *filename)
|
||||
{
|
||||
char *p;
|
||||
char *basename;
|
||||
char *reference;
|
||||
|
||||
p = strchr (filename, '-');
|
||||
if (!p)
|
||||
return NULL;
|
||||
|
||||
basename = g_strndup (filename, p - filename);
|
||||
reference = g_strconcat (basename, ".png", NULL);
|
||||
g_free (basename);
|
||||
|
||||
return reference;
|
||||
}
|
||||
|
||||
static void
|
||||
test_load_image (gconstpointer testdata)
|
||||
{
|
||||
const char *filename = testdata;
|
||||
GdkTexture *texture = NULL;
|
||||
GdkTexture *texture2;
|
||||
char *path;
|
||||
char *reference;
|
||||
char *path2;
|
||||
char *data;
|
||||
gsize size;
|
||||
GBytes *bytes;
|
||||
GError *error = NULL;
|
||||
|
||||
#ifndef HAVE_AVIF
|
||||
g_test_skip ("built without avif support");
|
||||
return;
|
||||
#endif
|
||||
|
||||
reference = get_reference (filename);
|
||||
if (!reference)
|
||||
{
|
||||
g_test_skip ("no reference image");
|
||||
return;
|
||||
}
|
||||
|
||||
path = g_test_build_filename (G_TEST_DIST, "yuv-images", filename, NULL);
|
||||
|
||||
g_file_get_contents (path, &data, &size, &error);
|
||||
g_assert_no_error (error);
|
||||
bytes = g_bytes_new_take (data, size);
|
||||
|
||||
#ifdef HAVE_AVIF
|
||||
texture = gdk_load_avif (bytes, &error);
|
||||
#endif
|
||||
|
||||
g_bytes_unref (bytes);
|
||||
|
||||
if (texture == NULL)
|
||||
{
|
||||
g_test_skip_printf ("unsupported format: %s", error->message);
|
||||
g_error_free (error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!GDK_IS_DMABUF_TEXTURE (texture))
|
||||
{
|
||||
g_test_message ("No dmabuf texture. /dev/udmabuf not available?");
|
||||
}
|
||||
|
||||
path2 = g_test_build_filename (G_TEST_DIST, "yuv-images", reference, NULL);
|
||||
texture2 = gdk_texture_new_from_filename (path2, &error);
|
||||
g_assert_no_error (error);
|
||||
g_assert_true (GDK_IS_TEXTURE (texture2));
|
||||
|
||||
assert_texture_equal (texture, texture2);
|
||||
|
||||
g_object_unref (texture);
|
||||
g_object_unref (texture2);
|
||||
g_free (path);
|
||||
g_free (path2);
|
||||
g_free (reference);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
char *path;
|
||||
GDir *dir;
|
||||
const char *name;
|
||||
GError *error = NULL;
|
||||
|
||||
gtk_init ();
|
||||
|
||||
(g_test_init) (&argc, &argv, NULL);
|
||||
|
||||
path = g_test_build_filename (G_TEST_DIST, "yuv-images", NULL);
|
||||
dir = g_dir_open (path, 0, &error);
|
||||
g_assert_no_error (error);
|
||||
g_free (path);
|
||||
|
||||
while ((name = g_dir_read_name (dir)) != NULL)
|
||||
{
|
||||
if (!g_str_has_suffix (name, ".png"))
|
||||
{
|
||||
char *test = g_strconcat ("/yuv/load/", name, NULL);
|
||||
g_test_add_data_func (test, name, test_load_image);
|
||||
g_free (test);
|
||||
}
|
||||
}
|
||||
|
||||
return g_test_run ();
|
||||
}
|
@@ -79,10 +79,10 @@ do_compare (int *argc,
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
texture[i] = gdk_texture_new_from_filename (filenames[i], &error);
|
||||
texture[i] = load_image_file (filenames[i]);
|
||||
if (texture[i] == NULL)
|
||||
{
|
||||
g_printerr (_("Failed to load %s: %s\n"), filenames[i], error->message);
|
||||
g_printerr (_("Failed to load %s\n"), filenames[i]);
|
||||
exit (1);
|
||||
}
|
||||
}
|
||||
|
@@ -31,10 +31,10 @@
|
||||
|
||||
|
||||
static void
|
||||
save_image (const char *filename,
|
||||
const char *output,
|
||||
GdkMemoryFormat format,
|
||||
GdkColorState *color_state)
|
||||
convert_image (const char *filename,
|
||||
const char *output,
|
||||
GdkMemoryFormat format,
|
||||
GdkColorState *color_state)
|
||||
{
|
||||
GdkTexture *orig;
|
||||
GdkTextureDownloader *downloader;
|
||||
@@ -61,10 +61,7 @@ save_image (const char *filename,
|
||||
|
||||
texture = gdk_memory_texture_builder_build (builder);
|
||||
|
||||
if (g_str_has_suffix (output, ".tiff"))
|
||||
gdk_texture_save_to_tiff (texture, output);
|
||||
else
|
||||
gdk_texture_save_to_png (texture, output);
|
||||
save_texture (texture, output);
|
||||
|
||||
g_object_unref (texture);
|
||||
g_bytes_unref (bytes);
|
||||
@@ -173,7 +170,7 @@ do_convert (int *argc,
|
||||
if (!color_state)
|
||||
color_state = gdk_color_state_get_srgb ();
|
||||
|
||||
save_image (filenames[0], filenames[1], format, color_state);
|
||||
convert_image (filenames[0], filenames[1], format, color_state);
|
||||
|
||||
g_strfreev (filenames);
|
||||
}
|
||||
|
@@ -48,12 +48,23 @@ static void
|
||||
file_info (const char *filename)
|
||||
{
|
||||
GdkTexture *texture;
|
||||
char *name;
|
||||
char *cicp;
|
||||
|
||||
texture = load_image_file (filename);
|
||||
|
||||
g_print ("%s %dx%d\n", _("Size:"), gdk_texture_get_width (texture), gdk_texture_get_height (texture));
|
||||
g_print ("%s %s\n", _("Format:"), get_format_name (gdk_texture_get_format (texture)));
|
||||
g_print ("%s %s\n", _("Color state:"), get_color_state_name (gdk_texture_get_color_state (texture)));
|
||||
|
||||
name = get_color_state_name (gdk_texture_get_color_state (texture));
|
||||
cicp = get_color_state_cicp (gdk_texture_get_color_state (texture));
|
||||
|
||||
if (name && cicp)
|
||||
g_print ("%s %s (cicp %s)\n", _("Color state:"), name, cicp);
|
||||
else if (cicp)
|
||||
g_print ("%s cicp %s\n", _("Color state:"), cicp);
|
||||
else
|
||||
g_print ("%s %s\n", _("Color state:"), _("unknown"));
|
||||
|
||||
g_object_unref (texture);
|
||||
}
|
||||
|
@@ -60,10 +60,7 @@ relabel_image (const char *filename,
|
||||
|
||||
texture = gdk_memory_texture_builder_build (builder);
|
||||
|
||||
if (g_str_has_suffix (output, ".tiff"))
|
||||
gdk_texture_save_to_tiff (texture, output);
|
||||
else
|
||||
gdk_texture_save_to_png (texture, output);
|
||||
save_texture (texture, output);
|
||||
|
||||
g_object_unref (texture);
|
||||
g_bytes_unref (bytes);
|
||||
|
@@ -28,15 +28,29 @@
|
||||
#include <glib/gstdio.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include "gtk-image-tool.h"
|
||||
|
||||
#include "gdk/loaders/gdkavifprivate.h"
|
||||
|
||||
GdkTexture *
|
||||
load_image_file (const char *filename)
|
||||
{
|
||||
GError *error = NULL;
|
||||
GdkTexture *texture;
|
||||
GdkTexture *texture = NULL;
|
||||
char *data;
|
||||
gsize size;
|
||||
GBytes *bytes;
|
||||
|
||||
if (g_file_get_contents (filename, &data, &size, &error))
|
||||
{
|
||||
bytes = g_bytes_new_take (data, size);
|
||||
|
||||
#ifdef HAVE_AVIF
|
||||
if (gdk_is_avif (bytes))
|
||||
texture = gdk_load_avif (bytes, &error);
|
||||
else
|
||||
#endif
|
||||
texture = gdk_texture_new_from_bytes (bytes, &error);
|
||||
}
|
||||
|
||||
texture = gdk_texture_new_from_filename (filename, &error);
|
||||
if (!texture)
|
||||
{
|
||||
g_printerr ("%s\n", error->message);
|
||||
@@ -44,9 +58,39 @@ load_image_file (const char *filename)
|
||||
exit (1);
|
||||
}
|
||||
|
||||
g_bytes_unref (bytes);
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
gboolean
|
||||
save_texture (GdkTexture *texture,
|
||||
const char *filename)
|
||||
{
|
||||
if (g_str_has_suffix (filename, ".png"))
|
||||
return gdk_texture_save_to_png (texture, filename);
|
||||
else if (g_str_has_suffix (filename, ".tiff"))
|
||||
return gdk_texture_save_to_tiff (texture, filename);
|
||||
#ifdef HAVE_AVIF
|
||||
else if (g_str_has_suffix (filename, ".avif"))
|
||||
{
|
||||
GBytes *bytes;
|
||||
gboolean result;
|
||||
|
||||
bytes = gdk_save_avif (texture);
|
||||
result = g_file_set_contents (filename,
|
||||
g_bytes_get_data (bytes, NULL),
|
||||
g_bytes_get_size (bytes),
|
||||
NULL);
|
||||
g_bytes_unref (bytes);
|
||||
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
find_format_by_name (const char *name,
|
||||
GdkMemoryFormat *format)
|
||||
@@ -149,6 +193,17 @@ find_color_state_by_name (const char *name)
|
||||
gdk_cicp_params_set_matrix_coefficients (params, 6);
|
||||
gdk_cicp_params_set_range (params, GDK_CICP_RANGE_NARROW);
|
||||
|
||||
color_state = gdk_cicp_params_build_color_state (params, &error);
|
||||
}
|
||||
else if (g_strcmp0 (name, "jpeg") == 0)
|
||||
{
|
||||
params = gdk_cicp_params_new ();
|
||||
|
||||
gdk_cicp_params_set_color_primaries (params, 1);
|
||||
gdk_cicp_params_set_transfer_function (params, 13);
|
||||
gdk_cicp_params_set_matrix_coefficients (params, 6);
|
||||
gdk_cicp_params_set_range (params, GDK_CICP_RANGE_FULL);
|
||||
|
||||
color_state = gdk_cicp_params_build_color_state (params, &error);
|
||||
}
|
||||
else if (g_strcmp0 (name, "bt709") == 0)
|
||||
@@ -181,13 +236,34 @@ get_color_state_names (void)
|
||||
static const char *names[] = {
|
||||
"srgb", "srgb-linear", "display-p3", "rec2020",
|
||||
"rec2100-pq", "rec2100-linear", "rec2100-hlg",
|
||||
"yuv", "bt601", "bt709",
|
||||
"yuv", "jpeg", "bt601", "bt709",
|
||||
NULL,
|
||||
};
|
||||
|
||||
return g_strdupv ((char **) names);
|
||||
}
|
||||
|
||||
char *
|
||||
get_color_state_cicp (GdkColorState *color_state)
|
||||
{
|
||||
GdkCicpParams *params;
|
||||
char *str = NULL;
|
||||
|
||||
params = gdk_color_state_create_cicp_params (color_state);
|
||||
|
||||
if (params)
|
||||
{
|
||||
str = g_strdup_printf ("%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);
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
char *
|
||||
get_color_state_name (GdkColorState *color_state)
|
||||
{
|
||||
|
@@ -8,7 +8,8 @@ void do_relabel (int *argc, const char ***argv);
|
||||
void do_show (int *argc, const char ***argv);
|
||||
|
||||
GdkTexture * load_image_file (const char *filename);
|
||||
|
||||
gboolean save_texture (GdkTexture *texture,
|
||||
const char *filename);
|
||||
|
||||
gboolean find_format_by_name (const char *name,
|
||||
GdkMemoryFormat *format);
|
||||
@@ -17,6 +18,7 @@ GdkColorState * find_color_state_by_name (const char *name);
|
||||
|
||||
char ** get_color_state_names (void);
|
||||
char * get_color_state_name (GdkColorState *color_state);
|
||||
char * get_color_state_cicp (GdkColorState *color_state);
|
||||
|
||||
GdkColorState *parse_cicp_tuple (const char *cicp_tuple,
|
||||
GError **error);
|
||||
|
@@ -22,6 +22,12 @@ if win32_enabled
|
||||
extra_update_icon_cache_objs = import('windows').compile_resources(uac_rc)
|
||||
endif
|
||||
|
||||
extra_image_tool_sources = []
|
||||
|
||||
if avif_dep.found()
|
||||
extra_image_tool_sources = ['../gdk/loaders/gdkavif.c']
|
||||
endif
|
||||
|
||||
gtk_tools = [
|
||||
['gtk4-path-tool', ['gtk-path-tool.c',
|
||||
'gtk-path-tool-decompose.c',
|
||||
@@ -56,7 +62,8 @@ gtk_tools = [
|
||||
'gtk-image-tool-relabel.c',
|
||||
'gtk-image-tool-show.c',
|
||||
'gtk-image-tool-utils.c',
|
||||
'../testsuite/reftests/reftest-compare.c'], [libgtk_dep] ],
|
||||
'../testsuite/reftests/reftest-compare.c'] + extra_image_tool_sources,
|
||||
[libgtk_dep] ],
|
||||
['gtk4-update-icon-cache', ['updateiconcache.c', '../gtk/gtkiconcachevalidator.c' ] + extra_update_icon_cache_objs, [ libgtk_dep ] ],
|
||||
['gtk4-encode-symbolic-svg', ['encodesymbolic.c'], [ libgtk_static_dep ] ],
|
||||
]
|
||||
@@ -73,7 +80,7 @@ foreach tool: gtk_tools
|
||||
exe = executable(tool_name,
|
||||
sources: tool_srcs,
|
||||
include_directories: [confinc],
|
||||
c_args: common_cflags + [ '-DBUILD_TOOLS' ],
|
||||
c_args: common_cflags + [ '-DBUILD_TOOLS', '-DAVIF_DEBUG' ],
|
||||
dependencies: tool_deps,
|
||||
install: true,
|
||||
)
|
||||
|