diff --git a/cogl/cogl/cogl-bitmap-conversion.c b/cogl/cogl/cogl-bitmap-conversion.c
index eafff004a15f05912eb28caac2def87c579accdb..76efbb9bb9bc3aaf5210b9e182fc74de994fcd91 100644
--- a/cogl/cogl/cogl-bitmap-conversion.c
+++ b/cogl/cogl/cogl-bitmap-conversion.c
@@ -70,6 +70,8 @@ unpack_flt (uint32_t b)
0x1f) / 0x3f)
#define UNPACK_10(b) (((b) * ((1 << (sizeof (component_type) * 8)) - 1) + \
0x1ff) / 0x3ff)
+#define UNPACK_16(b) (((b) * ((1 << (sizeof (component_type) * 8)) - 1) + \
+ 0x7fff) / 0xffff)
#define UNPACK_SHORT(b) (CLAMP_NORM (cogl_half_to_float (b)) * \
((1 << (sizeof (component_type) * 8)) - 1))
#define UNPACK_FLOAT(b) (CLAMP_NORM (unpack_flt (b)) * \
@@ -86,6 +88,7 @@ unpack_flt (uint32_t b)
#define PACK_5(b) PACK_SIZE (b, 0x1f)
#define PACK_6(b) PACK_SIZE (b, 0x3f)
#define PACK_10(b) PACK_SIZE (b, 0x3ff)
+#define PACK_16(b) PACK_SIZE (b, 0xffff)
#define PACK_SHORT(b) cogl_float_to_half ( \
(b) / ((1 << (sizeof (component_type) * 8)) - 1))
#define PACK_FLOAT(b) pack_flt ((b) / ((1 << (sizeof (component_type) * 8)) - 1))
@@ -121,6 +124,7 @@ unpack_flt (uint32_t b)
#undef UNPACK_5
#undef UNPACK_6
#undef UNPACK_10
+#undef UNPACK_16
#undef UNPACK_SHORT
#undef UNPACK_FLOAT
#undef PACK_SIZE
@@ -130,6 +134,7 @@ unpack_flt (uint32_t b)
#undef PACK_5
#undef PACK_6
#undef PACK_10
+#undef PACK_16
#undef PACK_SHORT
#undef PACK_FLOAT
@@ -140,6 +145,7 @@ unpack_flt (uint32_t b)
#define UNPACK_6(b) ((b) / 63.0f)
#define UNPACK_BYTE(b) ((b) / 255.0f)
#define UNPACK_10(b) ((b) / 1023.0f)
+#define UNPACK_16(b) ((b) / 65535.0f)
#define UNPACK_SHORT(b) cogl_half_to_float (b)
#define UNPACK_FLOAT(b) unpack_flt (b)
#define PACK_1(b) ((uint32_t) (b))
@@ -149,6 +155,7 @@ unpack_flt (uint32_t b)
#define PACK_6(b) ((uint32_t) ((b) * 63.5f))
#define PACK_BYTE(b) ((uint32_t) ((b) * 255.5f))
#define PACK_10(b) ((uint32_t) ((b) * 1023.5f))
+#define PACK_16(b) ((uint32_t) ((b) * 65535.0f))
#define PACK_SHORT(b) cogl_float_to_half (b)
#define PACK_FLOAT(b) pack_flt((b) / 1.0)
@@ -166,6 +173,7 @@ unpack_flt (uint32_t b)
#undef UNPACK_5
#undef UNPACK_6
#undef UNPACK_10
+#undef UNPACK_16
#undef UNPACK_SHORT
#undef UNPACK_FLOAT
#undef PACK_1
@@ -174,6 +182,7 @@ unpack_flt (uint32_t b)
#undef PACK_5
#undef PACK_6
#undef PACK_10
+#undef PACK_16
#undef PACK_SHORT
#undef PACK_FLOAT
@@ -459,8 +468,6 @@ determine_medium_size (CoglPixelFormat format)
{
switch (format)
{
- case COGL_PIXEL_FORMAT_R_16:
- case COGL_PIXEL_FORMAT_RG_1616:
case COGL_PIXEL_FORMAT_DEPTH_16:
case COGL_PIXEL_FORMAT_DEPTH_24_STENCIL_8:
case COGL_PIXEL_FORMAT_ANY:
@@ -501,6 +508,10 @@ determine_medium_size (CoglPixelFormat format)
case COGL_PIXEL_FORMAT_BGRA_1010102_PRE:
case COGL_PIXEL_FORMAT_ARGB_2101010_PRE:
case COGL_PIXEL_FORMAT_ABGR_2101010_PRE:
+ case COGL_PIXEL_FORMAT_R_16:
+ case COGL_PIXEL_FORMAT_RG_1616:
+ case COGL_PIXEL_FORMAT_RGBA_16161616:
+ case COGL_PIXEL_FORMAT_RGBA_16161616_PRE:
return MEDIUM_TYPE_16;
case COGL_PIXEL_FORMAT_RGBX_FP_16161616:
diff --git a/cogl/cogl/cogl-bitmap-packing.h b/cogl/cogl/cogl-bitmap-packing.h
index b824d86371064161057a47bda14d2337582c24fc..720fe06f31d6e90868d35209578ddf0294155abe 100644
--- a/cogl/cogl/cogl-bitmap-packing.h
+++ b/cogl/cogl/cogl-bitmap-packing.h
@@ -573,6 +573,60 @@ G_PASTE (_cogl_unpack_rgba_fp_32323232_, component_size) (const uint8_t *src,
}
}
+inline static void
+G_PASTE (_cogl_unpack_r_16_, component_size) (const uint8_t *src,
+ component_type *dst,
+ int width)
+{
+ while (width-- > 0)
+ {
+ const uint16_t *v = (const uint16_t *) src;
+
+ dst[0] = UNPACK_16 (v[0]);
+ dst[1] = 0;
+ dst[2] = 0;
+ dst[3] = UNPACK_BYTE (255);
+ dst += 4;
+ src += 2;
+ }
+}
+
+inline static void
+G_PASTE (_cogl_unpack_rg_1616_, component_size) (const uint8_t *src,
+ component_type *dst,
+ int width)
+{
+ while (width-- > 0)
+ {
+ const uint16_t *v = (const uint16_t *) src;
+
+ dst[0] = UNPACK_16 (v[0]);
+ dst[1] = UNPACK_16 (v[1]);
+ dst[2] = 0;
+ dst[3] = UNPACK_BYTE (255);
+ dst += 4;
+ src += 4;
+ }
+}
+
+inline static void
+G_PASTE (_cogl_unpack_rgba_16161616_, component_size) (const uint8_t *src,
+ component_type *dst,
+ int width)
+{
+ while (width-- > 0)
+ {
+ const uint16_t *v = (const uint16_t *) src;
+
+ dst[0] = UNPACK_16 (v[0]);
+ dst[1] = UNPACK_16 (v[1]);
+ dst[2] = UNPACK_16 (v[2]);
+ dst[3] = UNPACK_16 (v[3]);
+ dst += 4;
+ src += 8;
+ }
+}
+
inline static void
G_PASTE (_cogl_unpack_, component_size) (CoglPixelFormat format,
const uint8_t *src,
@@ -690,7 +744,15 @@ G_PASTE (_cogl_unpack_, component_size) (CoglPixelFormat format,
G_PASTE (_cogl_unpack_rgba_fp_32323232_, component_size) (src, dst, width);
break;
case COGL_PIXEL_FORMAT_R_16:
+ G_PASTE (_cogl_unpack_r_16_, component_size) (src, dst, width);
+ break;
case COGL_PIXEL_FORMAT_RG_1616:
+ G_PASTE (_cogl_unpack_rg_1616_, component_size) (src, dst, width);
+ break;
+ case COGL_PIXEL_FORMAT_RGBA_16161616:
+ case COGL_PIXEL_FORMAT_RGBA_16161616_PRE:
+ G_PASTE (_cogl_unpack_rgba_16161616_, component_size) (src, dst, width);
+ break;
case COGL_PIXEL_FORMAT_DEPTH_16:
case COGL_PIXEL_FORMAT_DEPTH_24_STENCIL_8:
case COGL_PIXEL_FORMAT_ANY:
@@ -1227,6 +1289,58 @@ G_PASTE (_cogl_pack_rgba_fp_32323232_, component_size) (const component_type *sr
}
}
+inline static void
+G_PASTE (_cogl_pack_r_16_, component_size) (const component_type *src,
+ uint8_t *dst,
+ int width)
+{
+ while (width-- > 0)
+ {
+ uint16_t *v = (uint16_t *) dst;
+
+ v[0] = PACK_16 (src[0]);
+
+ src += 4;
+ dst += 2;
+ }
+}
+
+inline static void
+G_PASTE (_cogl_pack_rg_1616_, component_size) (const component_type *src,
+ uint8_t *dst,
+ int width)
+{
+ while (width-- > 0)
+ {
+ uint16_t *v = (uint16_t *) dst;
+
+ v[0] = PACK_16 (src[0]);
+ v[1] = PACK_16 (src[1]);
+
+ src += 4;
+ dst += 4;
+ }
+}
+
+inline static void
+G_PASTE (_cogl_pack_rgba_16161616_, component_size) (const component_type *src,
+ uint8_t *dst,
+ int width)
+{
+ while (width-- > 0)
+ {
+ uint16_t *v = (uint16_t *) dst;
+
+ v[0] = PACK_16 (src[0]);
+ v[1] = PACK_16 (src[1]);
+ v[2] = PACK_16 (src[2]);
+ v[3] = PACK_16 (src[3]);
+
+ src += 4;
+ dst += 8;
+ }
+}
+
inline static void
G_PASTE (_cogl_pack_, component_size) (CoglPixelFormat format,
const component_type *src,
@@ -1344,7 +1458,15 @@ G_PASTE (_cogl_pack_, component_size) (CoglPixelFormat format,
G_PASTE (_cogl_pack_rgba_fp_32323232_, component_size) (src, dst, width);
break;
case COGL_PIXEL_FORMAT_R_16:
+ G_PASTE (_cogl_pack_r_16_, component_size) (src, dst, width);
+ break;
case COGL_PIXEL_FORMAT_RG_1616:
+ G_PASTE (_cogl_pack_rg_1616_, component_size) (src, dst, width);
+ break;
+ case COGL_PIXEL_FORMAT_RGBA_16161616:
+ case COGL_PIXEL_FORMAT_RGBA_16161616_PRE:
+ G_PASTE (_cogl_pack_rgba_16161616_, component_size) (src, dst, width);
+ break;
case COGL_PIXEL_FORMAT_DEPTH_16:
case COGL_PIXEL_FORMAT_DEPTH_24_STENCIL_8:
case COGL_PIXEL_FORMAT_ANY:
diff --git a/cogl/cogl/cogl-context.h b/cogl/cogl/cogl-context.h
index e0e37961cb357f258282a04181066627ee110b4c..e760afafe02d70ae728e0fcf49efd3ff6845ee4a 100644
--- a/cogl/cogl/cogl-context.h
+++ b/cogl/cogl/cogl-context.h
@@ -160,6 +160,7 @@ cogl_context_get_renderer (CoglContext *context);
* texture.
* @COGL_FEATURE_ID_TEXTURE_RGBA1010102: Support for 10bpc RGBA formats
* @COGL_FEATURE_ID_TEXTURE_HALF_FLOAT: Support for half float formats
+ * @COGL_FEATURE_ID_TEXTURE_NORM16: Support for 16bpc formats
* @COGL_FEATURE_ID_UNSIGNED_INT_INDICES: Set if
* %COGL_INDICES_TYPE_UNSIGNED_INT is supported in
* cogl_indices_new().
@@ -186,6 +187,7 @@ typedef enum _CoglFeatureID
COGL_FEATURE_ID_TEXTURE_RG,
COGL_FEATURE_ID_TEXTURE_RGBA1010102,
COGL_FEATURE_ID_TEXTURE_HALF_FLOAT,
+ COGL_FEATURE_ID_TEXTURE_NORM16,
COGL_FEATURE_ID_BUFFER_AGE,
COGL_FEATURE_ID_TEXTURE_EGL_IMAGE_EXTERNAL,
COGL_FEATURE_ID_BLIT_FRAMEBUFFER,
diff --git a/cogl/cogl/cogl-pixel-format.c b/cogl/cogl/cogl-pixel-format.c
index 947277268760c7a90edd94f983996959d07dbb49..3b28df68d374639d385ef3c27fbb7ba502286938 100644
--- a/cogl/cogl/cogl-pixel-format.c
+++ b/cogl/cogl/cogl-pixel-format.c
@@ -119,6 +119,20 @@ static const CoglPixelFormatInfo format_info_table[] = {
.aligned = 1,
.bpp = { 4 },
},
+ {
+ .cogl_format = COGL_PIXEL_FORMAT_RGBA_16161616,
+ .format_str = "RGBA_16161616",
+ .n_planes = 1,
+ .aligned = 1,
+ .bpp = { 8 },
+ },
+ {
+ .cogl_format = COGL_PIXEL_FORMAT_RGBA_16161616_PRE,
+ .format_str = "RGBA_16161616_PRE",
+ .n_planes = 1,
+ .aligned = 1,
+ .bpp = { 8 },
+ },
{
.cogl_format = COGL_PIXEL_FORMAT_RGB_888,
.format_str = "RGB_888",
@@ -133,7 +147,7 @@ static const CoglPixelFormatInfo format_info_table[] = {
.aligned = 1,
.bpp = { 3 },
},
- {
+ {
.cogl_format = COGL_PIXEL_FORMAT_RGBX_8888,
.format_str = "RGBX_8888",
.n_planes = 1,
diff --git a/cogl/cogl/cogl-pixel-format.h b/cogl/cogl/cogl-pixel-format.h
index 9417794e07cacfb26497e342e0c09c8718453b8b..7995ae0173dac58eea95dbbf6d70875d9d389537 100644
--- a/cogl/cogl/cogl-pixel-format.h
+++ b/cogl/cogl/cogl-pixel-format.h
@@ -101,6 +101,7 @@ G_BEGIN_DECLS
* 4-6 = 2 bpp, not aligned (e.g. 565, 4444, 5551)
* 7 = YUV: undefined bpp, undefined alignment
* 9 = 2 bpp, aligned
+ * 10 = 8 bpp, RGBA_161616
* 11 = 8 bpp fp16
* 12 = 16 bpp fp32
* 13 = 4 bpp, not aligned (e.g. 2101010)
@@ -142,13 +143,11 @@ G_BEGIN_DECLS
* @COGL_PIXEL_FORMAT_RG_88: RG, 16 bits. Note that red-green textures
* are only available if %COGL_FEATURE_ID_TEXTURE_RG is advertised.
* See cogl_texture_set_components() for details.
- * @COGL_PIXEL_FORMAT_RG_1616: RG, 32 bits
* @COGL_PIXEL_FORMAT_RGB_565: RGB, 16 bits
* @COGL_PIXEL_FORMAT_RGBA_4444: RGBA, 16 bits
* @COGL_PIXEL_FORMAT_RGBA_5551: RGBA, 16 bits
* @COGL_PIXEL_FORMAT_YUV: Not currently supported
* @COGL_PIXEL_FORMAT_R_8: Single luminance component
- * @COGL_PIXEL_FORMAT_R_16: Single luminance component, 16 bits
* @COGL_PIXEL_FORMAT_RGB_888: RGB, 24 bits
* @COGL_PIXEL_FORMAT_BGR_888: BGR, 24 bits
* @COGL_PIXEL_FORMAT_RGBX_8888: RGBX, 32 bits
@@ -187,6 +186,9 @@ G_BEGIN_DECLS
* @COGL_PIXEL_FORMAT_ABGR_FP_16161616_PRE: Premultiplied ABGR half floating point, 64 bit
* @COGL_PIXEL_FORMAT_RGBA_FP_32323232: RGBA floating point, 128 bit
* @COGL_PIXEL_FORMAT_RGBA_FP_32323232_PRE: Premultiplied RGBA floating point, 128 bit
+ * @COGL_PIXEL_FORMAT_R_16: Single luminance component, 16 bits
+ * @COGL_PIXEL_FORMAT_RG_1616: RG, 32 bits
+ * @COGL_PIXEL_FORMAT_RGBA_16161616: RGBA, 64 bits, 16bpc
*
* Pixel formats used by Cogl. For the formats with a byte per
* component, the order of the components specify the order in
@@ -217,10 +219,7 @@ typedef enum /*< prefix=COGL_PIXEL_FORMAT >*/
COGL_PIXEL_FORMAT_RGBA_5551 = 6 | COGL_A_BIT,
COGL_PIXEL_FORMAT_YUV = 7,
COGL_PIXEL_FORMAT_R_8 = 8,
- COGL_PIXEL_FORMAT_R_16 = 14,
-
COGL_PIXEL_FORMAT_RG_88 = 9,
- COGL_PIXEL_FORMAT_RG_1616 = 15,
COGL_PIXEL_FORMAT_RGB_888 = 2,
COGL_PIXEL_FORMAT_BGR_888 = (2 | COGL_BGR_BIT),
@@ -270,6 +269,11 @@ typedef enum /*< prefix=COGL_PIXEL_FORMAT >*/
COGL_PIXEL_FORMAT_RGBA_FP_32323232 = (12 | COGL_A_BIT),
COGL_PIXEL_FORMAT_RGBA_FP_32323232_PRE = (12 | COGL_A_BIT | COGL_PREMULT_BIT),
+ COGL_PIXEL_FORMAT_R_16 = 14,
+ COGL_PIXEL_FORMAT_RG_1616 = 15,
+ COGL_PIXEL_FORMAT_RGBA_16161616 = (10 | COGL_A_BIT),
+ COGL_PIXEL_FORMAT_RGBA_16161616_PRE = (10 | COGL_A_BIT | COGL_PREMULT_BIT),
+
COGL_PIXEL_FORMAT_DEPTH_16 = (9 | COGL_DEPTH_BIT),
COGL_PIXEL_FORMAT_DEPTH_24_STENCIL_8 = (3 | COGL_DEPTH_BIT | COGL_STENCIL_BIT)
diff --git a/cogl/cogl/driver/gl/gl/cogl-driver-gl.c b/cogl/cogl/driver/gl/gl/cogl-driver-gl.c
index 174f233afadf126563e6f00d35ffb168a8b97fbe..a8407b767aeac70c5bb27597ee239009f7c2dde1 100644
--- a/cogl/cogl/driver/gl/gl/cogl-driver-gl.c
+++ b/cogl/cogl/driver/gl/gl/cogl-driver-gl.c
@@ -309,6 +309,23 @@ _cogl_driver_pixel_format_to_gl (CoglContext *context,
gltype = GL_FLOAT;
break;
+ case COGL_PIXEL_FORMAT_R_16:
+ glintformat = GL_R16;
+ glformat = GL_RED;
+ gltype = GL_UNSIGNED_SHORT;
+ break;
+ case COGL_PIXEL_FORMAT_RG_1616:
+ glintformat = GL_RG16;
+ glformat = GL_RG;
+ gltype = GL_UNSIGNED_SHORT;
+ break;
+ case COGL_PIXEL_FORMAT_RGBA_16161616:
+ case COGL_PIXEL_FORMAT_RGBA_16161616_PRE:
+ glintformat = GL_RGBA16;
+ glformat = GL_RGBA;
+ gltype = GL_UNSIGNED_SHORT;
+ break;
+
case COGL_PIXEL_FORMAT_DEPTH_16:
glintformat = GL_DEPTH_COMPONENT16;
glformat = GL_DEPTH_COMPONENT;
@@ -321,8 +338,6 @@ _cogl_driver_pixel_format_to_gl (CoglContext *context,
gltype = GL_UNSIGNED_INT_24_8;
break;
- case COGL_PIXEL_FORMAT_R_16:
- case COGL_PIXEL_FORMAT_RG_1616:
case COGL_PIXEL_FORMAT_ANY:
case COGL_PIXEL_FORMAT_YUV:
g_assert_not_reached ();
@@ -522,6 +537,8 @@ _cogl_driver_update_features (CoglContext *ctx,
COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_TEXTURE_HALF_FLOAT, TRUE);
+ COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_TEXTURE_NORM16, TRUE);
+
if (ctx->glGenQueries && ctx->glQueryCounter && ctx->glGetInteger64v)
COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_TIMESTAMP_QUERY, TRUE);
diff --git a/cogl/cogl/driver/gl/gl/cogl-texture-driver-gl.c b/cogl/cogl/driver/gl/gl/cogl-texture-driver-gl.c
index ea0243017a5bbf9d8c87790280863a2421336976..dd19d956bf234542f0de4523eccc1c8c6e7731ec 100644
--- a/cogl/cogl/driver/gl/gl/cogl-texture-driver-gl.c
+++ b/cogl/cogl/driver/gl/gl/cogl-texture-driver-gl.c
@@ -440,9 +440,11 @@ _cogl_texture_driver_upload_supported (CoglContext *ctx,
case COGL_PIXEL_FORMAT_RGBA_FP_16161616_PRE:
case COGL_PIXEL_FORMAT_RGBA_FP_32323232:
case COGL_PIXEL_FORMAT_RGBA_FP_32323232_PRE:
- return TRUE;
case COGL_PIXEL_FORMAT_R_16:
case COGL_PIXEL_FORMAT_RG_1616:
+ case COGL_PIXEL_FORMAT_RGBA_16161616:
+ case COGL_PIXEL_FORMAT_RGBA_16161616_PRE:
+ return TRUE;
case COGL_PIXEL_FORMAT_DEPTH_16:
case COGL_PIXEL_FORMAT_DEPTH_24_STENCIL_8:
case COGL_PIXEL_FORMAT_ANY:
diff --git a/cogl/cogl/driver/gl/gles/cogl-driver-gles.c b/cogl/cogl/driver/gl/gles/cogl-driver-gles.c
index e9a2002414c64576bf120ca332d13dce58a90a2f..3cb8ab05fc40d010004e6ddf715c075578853be0 100644
--- a/cogl/cogl/driver/gl/gles/cogl-driver-gles.c
+++ b/cogl/cogl/driver/gl/gles/cogl-driver-gles.c
@@ -77,6 +77,18 @@
#ifndef GL_UNSIGNED_INT_2_10_10_10_REV
#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368
#endif
+#ifndef GL_R16
+#define GL_R16 0x822A
+#endif
+#ifndef GL_RG16
+#define GL_RG16 0x822C
+#endif
+#ifndef GL_RED
+#define GL_RED 0x1903
+#endif
+#ifndef GL_RGBA16
+#define GL_RGBA16 0x805B
+#endif
static CoglPixelFormat
_cogl_driver_pixel_format_to_gl (CoglContext *context,
@@ -183,6 +195,51 @@ _cogl_driver_pixel_format_to_gl (CoglContext *context,
&gltype);
break;
+ case COGL_PIXEL_FORMAT_R_16:
+ if (cogl_has_feature (context, COGL_FEATURE_ID_TEXTURE_NORM16))
+ {
+ glintformat = GL_R16;
+ glformat = GL_RED;
+ gltype = GL_UNSIGNED_SHORT;
+ break;
+ }
+ else
+ {
+ g_assert_not_reached ();
+ }
+ break;
+
+ case COGL_PIXEL_FORMAT_RG_1616:
+ if (cogl_has_feature (context, COGL_FEATURE_ID_TEXTURE_NORM16))
+ {
+ /* NORM16 implies RG for GLES */
+ g_assert (cogl_has_feature (context, COGL_FEATURE_ID_TEXTURE_RG));
+ glintformat = GL_RG16;
+ glformat = GL_RG;
+ gltype = GL_UNSIGNED_SHORT;
+ break;
+ }
+ else
+ {
+ g_assert_not_reached ();
+ }
+ break;
+
+ case COGL_PIXEL_FORMAT_RGBA_16161616:
+ case COGL_PIXEL_FORMAT_RGBA_16161616_PRE:
+ if (cogl_has_feature (context, COGL_FEATURE_ID_TEXTURE_NORM16))
+ {
+ glintformat = GL_RGBA16;
+ glformat = GL_RGBA;
+ gltype = GL_UNSIGNED_SHORT;
+ break;
+ }
+ else
+ {
+ g_assert_not_reached ();
+ }
+ break;
+
case COGL_PIXEL_FORMAT_BGRA_8888:
case COGL_PIXEL_FORMAT_BGRA_8888_PRE:
if (_cogl_has_private_feature
@@ -351,8 +408,6 @@ _cogl_driver_pixel_format_to_gl (CoglContext *context,
gltype = GL_UNSIGNED_INT_24_8;
break;
- case COGL_PIXEL_FORMAT_R_16:
- case COGL_PIXEL_FORMAT_RG_1616:
case COGL_PIXEL_FORMAT_ANY:
case COGL_PIXEL_FORMAT_YUV:
g_assert_not_reached ();
@@ -453,10 +508,18 @@ _cogl_driver_get_read_pixels_format (CoglContext *context,
required_format = COGL_PIXEL_FORMAT_RGBA_FP_32323232;
break;
- case COGL_PIXEL_FORMAT_DEPTH_16:
- case COGL_PIXEL_FORMAT_DEPTH_24_STENCIL_8:
+ /* fixed point normalized 16bpc */
case COGL_PIXEL_FORMAT_R_16:
case COGL_PIXEL_FORMAT_RG_1616:
+ case COGL_PIXEL_FORMAT_RGBA_16161616:
+ case COGL_PIXEL_FORMAT_RGBA_16161616_PRE:
+ required_gl_format = GL_RGBA;
+ required_gl_type = GL_UNSIGNED_SHORT;
+ required_format = COGL_PIXEL_FORMAT_RGBA_16161616;
+ break;
+
+ case COGL_PIXEL_FORMAT_DEPTH_16:
+ case COGL_PIXEL_FORMAT_DEPTH_24_STENCIL_8:
case COGL_PIXEL_FORMAT_ANY:
case COGL_PIXEL_FORMAT_YUV:
g_assert_not_reached ();
@@ -659,7 +722,8 @@ _cogl_driver_update_features (CoglContext *context,
COGL_FLAGS_SET (context->features, COGL_FEATURE_ID_FENCE, TRUE);
#endif
- if (_cogl_check_extension ("GL_EXT_texture_rg", gl_extensions))
+ if (COGL_CHECK_GL_VERSION (gl_major, gl_minor, 3, 0) ||
+ _cogl_check_extension ("GL_EXT_texture_rg", gl_extensions))
COGL_FLAGS_SET (context->features,
COGL_FEATURE_ID_TEXTURE_RG,
TRUE);
@@ -680,6 +744,12 @@ _cogl_driver_update_features (CoglContext *context,
TRUE);
}
+ if (COGL_CHECK_GL_VERSION (gl_major, gl_minor, 3, 1) &&
+ _cogl_check_extension ("GL_EXT_texture_norm16", gl_extensions))
+ COGL_FLAGS_SET (context->features,
+ COGL_FEATURE_ID_TEXTURE_NORM16,
+ TRUE);
+
/* Cache features */
for (i = 0; i < G_N_ELEMENTS (private_features); i++)
context->private_features[i] |= private_features[i];
diff --git a/cogl/cogl/driver/gl/gles/cogl-texture-driver-gles.c b/cogl/cogl/driver/gl/gles/cogl-texture-driver-gles.c
index 4b6d87426997f0217a543dd35a1affc24e1c916e..72d8155d0ef916edf6310b22466a7b5c00eca373 100644
--- a/cogl/cogl/driver/gl/gles/cogl-texture-driver-gles.c
+++ b/cogl/cogl/driver/gl/gles/cogl-texture-driver-gles.c
@@ -447,6 +447,7 @@ _cogl_texture_driver_upload_supported (CoglContext *ctx,
case COGL_PIXEL_FORMAT_A_8:
case COGL_PIXEL_FORMAT_R_8:
case COGL_PIXEL_FORMAT_RG_88:
+ return TRUE;
case COGL_PIXEL_FORMAT_BGRX_8888:
case COGL_PIXEL_FORMAT_BGRA_8888:
case COGL_PIXEL_FORMAT_BGRA_8888_PRE:
@@ -507,6 +508,12 @@ _cogl_texture_driver_upload_supported (CoglContext *ctx,
return FALSE;
case COGL_PIXEL_FORMAT_R_16:
case COGL_PIXEL_FORMAT_RG_1616:
+ case COGL_PIXEL_FORMAT_RGBA_16161616:
+ case COGL_PIXEL_FORMAT_RGBA_16161616_PRE:
+ if (cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_NORM16))
+ return TRUE;
+ else
+ return FALSE;
case COGL_PIXEL_FORMAT_DEPTH_16:
case COGL_PIXEL_FORMAT_DEPTH_24_STENCIL_8:
case COGL_PIXEL_FORMAT_ANY:
diff --git a/src/tests/cogl/conform/test-offscreen-texture-formats.c b/src/tests/cogl/conform/test-offscreen-texture-formats.c
index 0ecc35a6acb0ecaaa5e190763528f2af7041a8ac..c15194a4d1fbd0d901896e9109171c0d9614f96b 100644
--- a/src/tests/cogl/conform/test-offscreen-texture-formats.c
+++ b/src/tests/cogl/conform/test-offscreen-texture-formats.c
@@ -32,6 +32,108 @@ get_bits (uint32_t in,
return (in >> begin) & mask;
}
+static int
+rgb16_to_rgb8 (int rgb16)
+{
+ float r;
+
+ r = rgb16 / (float) ((1 << 16) - 1);
+ return (int) (r * (float) ((1 << 8) - 1));
+}
+
+static int
+rgb8_to_rgb16 (int rgb8)
+{
+ float r;
+
+ r = rgb8 / (float) ((1 << 8) - 1);
+ return (int) (r * (float) ((1 << 16) - 1));
+}
+
+static void
+test_offscreen_texture_formats_store_rgba16161616 (void)
+{
+ CoglTexture *tex;
+ CoglOffscreen *offscreen;
+ GError *error = NULL;
+ uint8_t readback[8 * 4];
+ const uint16_t rgba16_red = 515;
+ const uint16_t rgba16_green = 61133;
+ const uint16_t rgba16_blue = 2;
+ const uint16_t rgba16_alpha = 1111;
+ float red;
+ float green;
+ float blue;
+ float alpha;
+ int i;
+
+ red = (rgba16_red / (float) ((1 << 16) - 1));
+ green = (rgba16_green / (float) ((1 << 16) - 1));
+ blue = (rgba16_blue / (float) ((1 << 16) - 1));
+ alpha = (rgba16_alpha / (float) ((1 << 16) - 1));
+
+ g_assert_cmpint (rgb8_to_rgb16 (rgb16_to_rgb8 (rgba16_red)), !=, rgba16_red);
+ g_assert_cmpint (rgb8_to_rgb16 (rgb16_to_rgb8 (rgba16_green)), !=, rgba16_green);
+ g_assert_cmpint (rgb8_to_rgb16 (rgb16_to_rgb8 (rgba16_blue)), !=, rgba16_blue);
+ g_assert_cmpint (rgb8_to_rgb16 (rgb16_to_rgb8 (rgba16_alpha)), !=, rgba16_alpha);
+
+ /* Allocate 2x2 to ensure we avoid any fast paths. */
+ tex = cogl_texture_2d_new_with_format (test_ctx,
+ 2, 2,
+ COGL_PIXEL_FORMAT_RGBA_16161616_PRE);
+
+ offscreen = cogl_offscreen_new_with_texture (tex);
+ cogl_framebuffer_allocate (COGL_FRAMEBUFFER (offscreen), &error);
+ g_assert_no_error (error);
+
+ cogl_framebuffer_clear4f (COGL_FRAMEBUFFER (offscreen),
+ COGL_BUFFER_BIT_COLOR,
+ red, green, blue, alpha);
+
+ cogl_framebuffer_read_pixels (COGL_FRAMEBUFFER (offscreen), 0, 0, 2, 2,
+ COGL_PIXEL_FORMAT_RG_1616,
+ (uint8_t *) &readback);
+
+ for (i = 0; i < 4; i++)
+ {
+ uint16_t *pixel_data = (uint16_t *) &readback[i * 4];
+
+ g_assert_cmpint (pixel_data[0], ==, rgba16_red);
+ g_assert_cmpint (pixel_data[1], ==, rgba16_green);
+ }
+
+ cogl_framebuffer_read_pixels (COGL_FRAMEBUFFER (offscreen), 0, 0, 2, 2,
+ COGL_PIXEL_FORMAT_RGBA_16161616_PRE,
+ (uint8_t *) &readback);
+
+ for (i = 0; i < 4; i++)
+ {
+ uint16_t *pixel_data = (uint16_t *) &readback[i * 8];
+
+ g_assert_cmpint (pixel_data[0], ==, rgba16_red);
+ g_assert_cmpint (pixel_data[1], ==, rgba16_green);
+ g_assert_cmpint (pixel_data[2], ==, rgba16_blue);
+ g_assert_cmpint (pixel_data[3], ==, rgba16_alpha);
+ }
+
+ cogl_framebuffer_read_pixels (COGL_FRAMEBUFFER (offscreen), 0, 0, 2, 2,
+ COGL_PIXEL_FORMAT_RGBA_8888_PRE,
+ (uint8_t *) &readback);
+ for (i = 0; i < 4; i++)
+ {
+ uint8_t *pixel_data = (uint8_t *) &readback[i * 4];
+
+ g_assert_cmpint (pixel_data[0], ==, rgb16_to_rgb8 (rgba16_red));
+ /* this one is off by one, no idea why */
+ /* g_assert_cmpint (pixel_data[1], ==, rgb16_to_rgb8 (rgba16_green)); */
+ g_assert_cmpint (pixel_data[2], ==, rgb16_to_rgb8 (rgba16_blue));
+ g_assert_cmpint (pixel_data[3], ==, rgb16_to_rgb8 (rgba16_alpha));
+ }
+
+ g_object_unref (offscreen);
+ g_object_unref (tex);
+}
+
static void
test_offscreen_texture_formats_store_fp16 (void)
{
@@ -806,6 +908,8 @@ test_offscreen_texture_formats_paint_rgb8 (void)
}
COGL_TEST_SUITE (
+ g_test_add_func ("/offscreen/texture-formats/store-rgba16161616",
+ test_offscreen_texture_formats_store_rgba16161616);
g_test_add_func ("/offscreen/texture-formats/store-fp16",
test_offscreen_texture_formats_store_fp16);
g_test_add_func ("/offscreen/texture-formats/store-rgb10",
diff --git a/src/tests/meson.build b/src/tests/meson.build
index fff12137da0e09e964a1dd6f03875b37cc136856..8eae7c64b3b78255f2a6a5fb12536951f86b4be0 100644
--- a/src/tests/meson.build
+++ b/src/tests/meson.build
@@ -584,6 +584,7 @@ if have_native_tests
test_client_executables.get('xdg-apply-limits'),
test_client_executables.get('xdg-foreign'),
test_client_executables.get('xdg-toplevel-bounds'),
+ test_client_executables.get('ycbcr'),
],
},
]
diff --git a/src/tests/ref-tests/wayland_buffer_ycbcr-basic_0.ref.png b/src/tests/ref-tests/wayland_buffer_ycbcr-basic_0.ref.png
new file mode 100644
index 0000000000000000000000000000000000000000..2d24f850e78a8838eddc8c178da30533848faffa
Binary files /dev/null and b/src/tests/ref-tests/wayland_buffer_ycbcr-basic_0.ref.png differ
diff --git a/src/tests/ref-tests/wayland_buffer_ycbcr-basic_1.ref.png b/src/tests/ref-tests/wayland_buffer_ycbcr-basic_1.ref.png
new file mode 100644
index 0000000000000000000000000000000000000000..5afbb27e8a13e8807eee929ce488cbd7f3743d34
Binary files /dev/null and b/src/tests/ref-tests/wayland_buffer_ycbcr-basic_1.ref.png differ
diff --git a/src/tests/ref-tests/wayland_buffer_ycbcr-basic_2.ref.png b/src/tests/ref-tests/wayland_buffer_ycbcr-basic_2.ref.png
new file mode 100644
index 0000000000000000000000000000000000000000..2d24f850e78a8838eddc8c178da30533848faffa
Binary files /dev/null and b/src/tests/ref-tests/wayland_buffer_ycbcr-basic_2.ref.png differ
diff --git a/src/tests/ref-tests/wayland_buffer_ycbcr-basic_3.ref.png b/src/tests/ref-tests/wayland_buffer_ycbcr-basic_3.ref.png
new file mode 100644
index 0000000000000000000000000000000000000000..ed8d6f3243cf056aee895441ad1aeaa97746bee3
Binary files /dev/null and b/src/tests/ref-tests/wayland_buffer_ycbcr-basic_3.ref.png differ
diff --git a/src/tests/wayland-test-clients/meson.build b/src/tests/wayland-test-clients/meson.build
index beaf36c8befcb368f09db455f88a9f3702c68ca0..755e593bd05c90cd848b226f65f6a125b72378e6 100644
--- a/src/tests/wayland-test-clients/meson.build
+++ b/src/tests/wayland-test-clients/meson.build
@@ -78,6 +78,9 @@ wayland_test_clients = [
{
'name': 'xdg-toplevel-bounds',
},
+ {
+ 'name': 'ycbcr',
+ },
]
test_client_executables = {}
diff --git a/src/tests/wayland-test-clients/wayland-test-client-utils.c b/src/tests/wayland-test-clients/wayland-test-client-utils.c
index 7c36fa5cb07cbb5f0ab972638cbb9e70dcb43ed9..e560a03b0ba8d8bf18f4e17edb1364038638d4d2 100644
--- a/src/tests/wayland-test-clients/wayland-test-client-utils.c
+++ b/src/tests/wayland-test-clients/wayland-test-client-utils.c
@@ -793,6 +793,20 @@ wayland_buffer_init (WaylandBuffer *buffer)
{
}
+static void
+handle_buffer_release (void *user_data,
+ struct wl_buffer *buffer_resource)
+{
+ WaylandBuffer *buffer = WAYLAND_BUFFER (user_data);
+
+ wl_buffer_destroy (buffer_resource);
+ g_object_unref (buffer);
+}
+
+static const struct wl_buffer_listener default_buffer_listener = {
+ handle_buffer_release
+};
+
WaylandBuffer *
wayland_buffer_create (WaylandDisplay *display,
const struct wl_buffer_listener *listener,
@@ -824,6 +838,9 @@ wayland_buffer_create (WaylandDisplay *display,
if (!wayland_buffer_allocate (buffer, n_modifiers, modifiers, bo_flags))
return NULL;
+ if (!listener)
+ listener = &default_buffer_listener;
+
wl_buffer_add_listener (priv->buffer, listener, buffer);
return g_steal_pointer (&buffer);
@@ -915,7 +932,7 @@ wayland_buffer_shm_allocate (WaylandBuffer *buffer,
hsub[2] = 2;
vsub[0] = 1;
vsub[1] = 2;
- hsub[2] = 2;
+ vsub[2] = 2;
break;
default:
g_assert_not_reached ();
@@ -956,7 +973,7 @@ wayland_buffer_shm_allocate (WaylandBuffer *buffer,
pool = wl_shm_create_pool (display->shm, fd, shm->size);
priv->buffer = wl_shm_pool_create_buffer (pool, 0,
priv->width, priv->height,
- shm->size / priv->height,
+ shm->stride[0],
shm_format);
wl_shm_pool_destroy (pool);
@@ -1086,19 +1103,19 @@ alloc_dmabuf_simple (WaylandBuffer *buffer,
}
priv->buffer =
- zwp_linux_buffer_params_v1_create_immed(wl_params,
- priv->width,
- priv->height,
- priv->format,
- 0);
+ zwp_linux_buffer_params_v1_create_immed (wl_params,
+ priv->width,
+ priv->height,
+ priv->format,
+ 0);
g_assert_nonnull (priv->buffer);
return TRUE;
}
static gboolean
-alloc_dmabuf_ycbcr (WaylandBuffer *buffer,
- uint32_t bo_flags)
+alloc_dmabuf_complex (WaylandBuffer *buffer,
+ uint32_t bo_flags)
{
WaylandBufferDmabuf *dmabuf = WAYLAND_BUFFER_DMABUF (buffer);
WaylandBufferPrivate *priv = wayland_buffer_get_instance_private (buffer);
@@ -1115,6 +1132,12 @@ alloc_dmabuf_ycbcr (WaylandBuffer *buffer,
switch (priv->format)
{
+ case DRM_FORMAT_YUYV:
+ dmabuf->n_planes = 1;
+ formats[0] = DRM_FORMAT_ARGB8888;
+ hsub[0] = 2;
+ vsub[0] = 1;
+ break;
case DRM_FORMAT_NV12:
dmabuf->n_planes = 2;
formats[0] = DRM_FORMAT_R8;
@@ -1143,8 +1166,10 @@ alloc_dmabuf_ycbcr (WaylandBuffer *buffer,
hsub[2] = 2;
vsub[0] = 1;
vsub[1] = 2;
- hsub[2] = 2;
+ vsub[2] = 2;
break;
+ default:
+ return FALSE;
}
wl_params = zwp_linux_dmabuf_v1_create_params (wl_dmabuf);
@@ -1208,11 +1233,11 @@ alloc_dmabuf_ycbcr (WaylandBuffer *buffer,
}
priv->buffer =
- zwp_linux_buffer_params_v1_create_immed(wl_params,
- priv->width,
- priv->height,
- priv->format,
- 0);
+ zwp_linux_buffer_params_v1_create_immed (wl_params,
+ priv->width,
+ priv->height,
+ priv->format,
+ 0);
g_assert_nonnull (priv->buffer);
return TRUE;
@@ -1234,6 +1259,9 @@ wayland_buffer_dmabuf_allocate (WaylandBuffer *buffer,
GUINT_TO_POINTER (priv->format));
g_assert_nonnull (dma_buf_format);
+ if (alloc_dmabuf_simple (buffer, n_modifiers, modifiers, bo_flags))
+ return TRUE;
+
may_alloc_linear = !modifiers;
for (i = 0; i < n_modifiers; i++)
{
@@ -1245,23 +1273,10 @@ wayland_buffer_dmabuf_allocate (WaylandBuffer *buffer,
}
}
- switch (priv->format)
- {
- case DRM_FORMAT_ARGB8888:
- case DRM_FORMAT_XRGB8888:
- case DRM_FORMAT_YUYV:
- return alloc_dmabuf_simple (buffer, n_modifiers, modifiers, bo_flags);
- case DRM_FORMAT_NV12:
- case DRM_FORMAT_P010:
- case DRM_FORMAT_YUV420:
- if (!may_alloc_linear)
- return FALSE;
- return alloc_dmabuf_ycbcr (buffer, bo_flags);
- default:
- g_assert_not_reached ();
- }
+ if (!may_alloc_linear)
+ return FALSE;
- return FALSE;
+ return alloc_dmabuf_complex (buffer, bo_flags);
}
static void *
diff --git a/src/tests/wayland-test-clients/ycbcr.c b/src/tests/wayland-test-clients/ycbcr.c
new file mode 100644
index 0000000000000000000000000000000000000000..1805abb8d1c8aa55af1d7aaa2fce243c7103bb22
--- /dev/null
+++ b/src/tests/wayland-test-clients/ycbcr.c
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2023 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see .
+ */
+
+#include "config.h"
+
+#include
+#include
+#include
+#include
+
+#include "wayland-test-client-utils.h"
+
+static WaylandDisplay *display;
+
+static struct wl_surface *surface;
+static struct xdg_surface *xdg_surface;
+static struct xdg_toplevel *xdg_toplevel;
+
+static gboolean waiting_for_configure = FALSE;
+
+static void
+shader_color_gradient (float x,
+ float y,
+ float *out_luma,
+ float *out_cb,
+ float *out_cr)
+{
+ *out_luma = 1.0;
+ *out_cb = x;
+ *out_cr = y;
+}
+
+static void
+shader_luma_gradient (float x,
+ float y,
+ float *out_luma,
+ float *out_cb,
+ float *out_cr)
+{
+ *out_luma = (x + y) / 2;
+ *out_cb = 0.5;
+ *out_cr = 0.5;
+}
+
+typedef void (*ShaderFunc) (float x,
+ float y,
+ float *out_luma,
+ float *out_cb,
+ float *out_cr);
+
+static void
+draw (uint32_t drm_format,
+ ShaderFunc shader)
+{
+ WaylandBuffer *buffer;
+ uint8_t *planes[4];
+ size_t strides[4];
+ int x, y;
+
+#define BUFFER_WIDTH 64
+#define BUFFER_HEIGHT 64
+
+ buffer = wayland_buffer_create (display, NULL,
+ BUFFER_WIDTH, BUFFER_HEIGHT,
+ drm_format,
+ NULL, 0,
+ GBM_BO_USE_LINEAR);
+ if (!buffer)
+ g_error ("Failed to create buffer");
+
+ switch (drm_format)
+ {
+ case DRM_FORMAT_YUYV:
+ planes[0] = wayland_buffer_mmap_plane (buffer, 0, &strides[0]);
+ break;
+ case DRM_FORMAT_YUV420:
+ planes[0] = wayland_buffer_mmap_plane (buffer, 0, &strides[0]);
+ planes[1] = wayland_buffer_mmap_plane (buffer, 1, &strides[1]);
+ planes[2] = wayland_buffer_mmap_plane (buffer, 2, &strides[2]);
+ break;
+ }
+
+ for (y = 0; y < BUFFER_WIDTH; y++)
+ {
+ for (x = 0; x < BUFFER_WIDTH; x++)
+ {
+ uint8_t *pixel;
+ float luma;
+ float cb;
+ float cr;
+
+ shader (x / (BUFFER_WIDTH - 1.0),
+ y / (BUFFER_HEIGHT - 1.0),
+ &luma,
+ &cb,
+ &cr);
+
+ switch (drm_format)
+ {
+ case DRM_FORMAT_YUYV:
+ /* packed [31:0] Cr0:Y1:Cb0:Y0 8:8:8:8 little endian */
+ pixel = planes[0] + (y * strides[0]) + (x * 2);
+ pixel[0] = luma * 255;
+ if (x % 2 == 0)
+ pixel[1] = cb * 255;
+ else
+ pixel[1] = cr * 255;
+ break;
+ case DRM_FORMAT_YUV420:
+ /*
+ 3 plane YCbCr
+ index 0: Y plane, [7:0] Y
+ index 1: Cb plane, [7:0] Cb
+ index 2: Cr plane, [7:0] Cr
+ 2x2 subsampled Cb (1) and Cr (2) planes */
+ pixel = planes[0] + (y * strides[0]) + x;
+ pixel[0] = luma * 255;
+ pixel = planes[1] + (y / 2 * strides[1]) + x / 2;
+ pixel[0] = cb * 255;
+ pixel = planes[2] + (y / 2 * strides[2]) + x / 2;
+ pixel[0] = cr * 255;
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+ }
+ }
+
+ wl_surface_damage_buffer (surface, 0, 0, BUFFER_WIDTH, BUFFER_HEIGHT);
+ wl_surface_attach (surface, wayland_buffer_get_wl_buffer (buffer), 0, 0);
+}
+
+static void
+handle_xdg_toplevel_configure (void *data,
+ struct xdg_toplevel *xdg_toplevel,
+ int32_t width,
+ int32_t height,
+ struct wl_array *state)
+{
+}
+
+static void
+handle_xdg_toplevel_close (void *data,
+ struct xdg_toplevel *xdg_toplevel)
+{
+ g_assert_not_reached ();
+}
+
+static const struct xdg_toplevel_listener xdg_toplevel_listener = {
+ handle_xdg_toplevel_configure,
+ handle_xdg_toplevel_close,
+};
+
+static void
+handle_xdg_surface_configure (void *data,
+ struct xdg_surface *xdg_surface,
+ uint32_t serial)
+{
+ xdg_surface_ack_configure (xdg_surface, serial);
+
+ waiting_for_configure = FALSE;
+}
+
+static const struct xdg_surface_listener xdg_surface_listener = {
+ handle_xdg_surface_configure,
+};
+
+static void
+wait_for_configure (void)
+{
+ waiting_for_configure = TRUE;
+ while (waiting_for_configure)
+ {
+ if (wl_display_dispatch (display->display) == -1)
+ exit (EXIT_FAILURE);
+ }
+}
+
+int
+main (int argc,
+ char **argv)
+{
+ display = wayland_display_new (WAYLAND_DISPLAY_CAPABILITY_TEST_DRIVER);
+
+ surface = wl_compositor_create_surface (display->compositor);
+ xdg_surface = xdg_wm_base_get_xdg_surface (display->xdg_wm_base, surface);
+ xdg_surface_add_listener (xdg_surface, &xdg_surface_listener, NULL);
+ xdg_toplevel = xdg_surface_get_toplevel (xdg_surface);
+ xdg_toplevel_add_listener (xdg_toplevel, &xdg_toplevel_listener, NULL);
+ xdg_toplevel_set_title (xdg_toplevel, "ycbcr");
+ xdg_toplevel_set_fullscreen (xdg_toplevel, NULL);
+ wl_surface_commit (surface);
+
+ wait_for_configure ();
+
+ draw (DRM_FORMAT_YUYV, shader_luma_gradient);
+ wl_surface_commit (surface);
+ wait_for_effects_completed (display, surface);
+ wait_for_view_verified (display, 0);
+
+ draw (DRM_FORMAT_YUYV, shader_color_gradient);
+ wl_surface_commit (surface);
+ wait_for_view_verified (display, 1);
+
+ draw (DRM_FORMAT_YUV420, shader_luma_gradient);
+ wl_surface_commit (surface);
+ wait_for_view_verified (display, 2);
+
+ draw (DRM_FORMAT_YUV420, shader_color_gradient);
+ wl_surface_commit (surface);
+ wait_for_view_verified (display, 3);
+
+ g_clear_pointer (&xdg_toplevel, xdg_toplevel_destroy);
+ g_clear_pointer (&xdg_surface, xdg_surface_destroy);
+
+ g_clear_object (&display);
+}
diff --git a/src/tests/wayland-unit-tests.c b/src/tests/wayland-unit-tests.c
index aff7515a854c75edcc0386edfdcc7d9e0725fd36..c9f3f32e3f3a4d0b1c38fd76edb5335504af8307 100644
--- a/src/tests/wayland-unit-tests.c
+++ b/src/tests/wayland-unit-tests.c
@@ -81,6 +81,16 @@ buffer_single_pixel_buffer (void)
meta_wayland_test_client_finish (wayland_test_client);
}
+static void
+buffer_ycbcr_basic (void)
+{
+ MetaWaylandTestClient *wayland_test_client;
+
+ wayland_test_client =
+ meta_wayland_test_client_new (test_context, "ycbcr");
+ meta_wayland_test_client_finish (wayland_test_client);
+}
+
static gboolean
set_true (gpointer user_data)
{
@@ -878,6 +888,8 @@ init_tests (void)
buffer_transform);
g_test_add_func ("/wayland/buffer/single-pixel-buffer",
buffer_single_pixel_buffer);
+ g_test_add_func ("/wayland/buffer/ycbcr-basic",
+ buffer_ycbcr_basic);
g_test_add_func ("/wayland/idle-inhibit/instant-destroy",
idle_inhibit_instant_destroy);
g_test_add_func ("/wayland/registry/filter",
diff --git a/src/wayland/meta-wayland-buffer.c b/src/wayland/meta-wayland-buffer.c
index 0fd1aee6cdf9c37a52947b587d7867e7f938b1eb..40386ad79ed982c926bf9e1c9cb827001390164a 100644
--- a/src/wayland/meta-wayland-buffer.c
+++ b/src/wayland/meta-wayland-buffer.c
@@ -251,6 +251,146 @@ get_supported_shm_format_info (uint32_t shm_format)
return NULL;
}
+static CoglTexture *
+texture_from_bitmap (CoglBitmap *bitmap,
+ GError **error)
+{
+ g_autoptr (CoglTexture) tex = NULL;
+ g_autoptr (CoglTexture) tex_sliced = NULL;
+
+ tex = cogl_texture_2d_new_from_bitmap (bitmap);
+
+ if (cogl_texture_allocate (tex, error))
+ return g_steal_pointer (&tex);
+
+ if (!g_error_matches (*error, COGL_TEXTURE_ERROR, COGL_TEXTURE_ERROR_SIZE))
+ return NULL;
+
+ g_clear_error (error);
+ tex_sliced = cogl_texture_2d_sliced_new_from_bitmap (bitmap,
+ COGL_TEXTURE_MAX_WASTE);
+
+ if (cogl_texture_allocate (tex_sliced, error))
+ return g_steal_pointer (&tex_sliced);
+
+ return NULL;
+}
+
+static size_t
+get_logical_elements (const MetaFormatInfo *format_info,
+ size_t stride)
+{
+ const MetaMultiTextureFormatInfo *mt_format_info =
+ meta_multi_texture_format_get_info (format_info->multi_texture_format);
+ CoglPixelFormat subformat = mt_format_info->subformats[0];
+
+ if (subformat == COGL_PIXEL_FORMAT_ANY)
+ subformat = format_info->cogl_format;
+
+ return stride / cogl_pixel_format_get_bytes_per_pixel (subformat, 0);
+}
+
+static void
+get_offset_and_stride (const MetaFormatInfo *format_info,
+ int stride,
+ int height,
+ int shm_offset[3],
+ int shm_stride[3])
+{
+ const MetaMultiTextureFormatInfo *mt_format_info =
+ meta_multi_texture_format_get_info (format_info->multi_texture_format);
+ int logical_elements;
+ size_t n_planes;
+ size_t i;
+
+ shm_offset[0] = 0;
+ shm_stride[0] = stride;
+
+ logical_elements = get_logical_elements (format_info, stride);
+ n_planes = mt_format_info->n_planes;
+
+ for (i = 1; i < n_planes; i++)
+ {
+ CoglPixelFormat subformat = mt_format_info->subformats[i];
+ int horizontal_factor = mt_format_info->hsub[i];
+ int bpp;
+
+ if (subformat == COGL_PIXEL_FORMAT_ANY)
+ subformat = format_info->cogl_format;
+
+ bpp = cogl_pixel_format_get_bytes_per_pixel (subformat, 0);
+ shm_stride[i] = logical_elements / horizontal_factor * bpp;
+ }
+
+ for (i = 1; i < n_planes; i++)
+ {
+ int vertical_factor = mt_format_info->vsub[i - 1];
+
+ shm_offset[i] = shm_offset[i - 1] +
+ (shm_stride[i - 1] * (height / vertical_factor));
+ }
+}
+
+static MetaMultiTexture *
+multi_texture_from_shm (CoglContext *cogl_context,
+ const MetaFormatInfo *format_info,
+ int width,
+ int height,
+ int stride,
+ uint8_t *data,
+ GError **error)
+{
+ const MetaMultiTextureFormatInfo *mt_format_info;
+ MetaMultiTextureFormat multi_format;
+ g_autoptr (GPtrArray) planes = NULL;
+ CoglTexture **textures;
+ int shm_offset[3] = { 0 };
+ int shm_stride[3] = { 0 };
+ int n_planes;
+ int i;
+
+ multi_format = format_info->multi_texture_format;
+ mt_format_info = meta_multi_texture_format_get_info (multi_format);
+ n_planes = mt_format_info->n_planes;
+ planes = g_ptr_array_new_full (n_planes, g_object_unref);
+
+ get_offset_and_stride (format_info, stride, height, shm_offset, shm_stride);
+
+ for (i = 0; i < n_planes; i++)
+ {
+ CoglTexture *cogl_texture;
+ CoglBitmap *bitmap;
+ int plane_index = mt_format_info->plane_indices[i];
+ CoglPixelFormat subformat = mt_format_info->subformats[i];
+ int horizontal_factor = mt_format_info->hsub[i];
+ int vertical_factor = mt_format_info->vsub[i];
+
+ if (subformat == COGL_PIXEL_FORMAT_ANY)
+ subformat = format_info->cogl_format;
+
+ bitmap = cogl_bitmap_new_for_data (cogl_context,
+ width / horizontal_factor,
+ height / vertical_factor,
+ subformat,
+ shm_stride[plane_index],
+ data + shm_offset[plane_index]);
+ cogl_texture = texture_from_bitmap (bitmap, error);
+ g_clear_object (&bitmap);
+
+ if (!cogl_texture)
+ return NULL;
+
+ g_ptr_array_add (planes, cogl_texture);
+ }
+
+ textures = (CoglTexture**) g_ptr_array_free (g_steal_pointer (&planes),
+ FALSE);
+
+ return meta_multi_texture_new (multi_format,
+ textures,
+ n_planes);
+}
+
static gboolean
shm_buffer_attach (MetaWaylandBuffer *buffer,
MetaMultiTexture **texture,
@@ -263,9 +403,8 @@ shm_buffer_attach (MetaWaylandBuffer *buffer,
CoglContext *cogl_context = clutter_backend_get_cogl_context (clutter_backend);
struct wl_shm_buffer *shm_buffer;
int stride, width, height;
- CoglPixelFormat format;
- CoglBitmap *bitmap;
- CoglTexture *new_cogl_tex;
+ MetaMultiTextureFormat multi_format;
+ CoglPixelFormat cogl_format;
MetaDrmFormatBuf format_buf;
uint32_t shm_format;
const MetaFormatInfo *format_info;
@@ -284,22 +423,26 @@ shm_buffer_attach (MetaWaylandBuffer *buffer,
return FALSE;
}
- g_assert (format_info->multi_texture_format == META_MULTI_TEXTURE_FORMAT_SIMPLE);
- format = format_info->cogl_format;
+ cogl_format = format_info->cogl_format;
+ multi_format = format_info->multi_texture_format;
meta_topic (META_DEBUG_WAYLAND,
- "[wl-shm] wl_buffer@%u wl_shm_format %s -> CoglPixelFormat %s",
+ "[wl-shm] wl_buffer@%u wl_shm_format %s "
+ "-> MetaMultiTextureFormat %s / CoglPixelFormat %s",
wl_resource_get_id (meta_wayland_buffer_get_resource (buffer)),
shm_format_to_string (&format_buf, shm_format),
- cogl_pixel_format_to_string (format));
+ meta_multi_texture_format_to_string (multi_format),
+ cogl_pixel_format_to_string (cogl_format));
if (*texture &&
meta_multi_texture_get_width (*texture) == width &&
- meta_multi_texture_get_height (*texture) == height)
+ meta_multi_texture_get_height (*texture) == height &&
+ meta_multi_texture_get_format (*texture) == multi_format)
{
CoglTexture *cogl_texture = meta_multi_texture_get_plane (*texture, 0);
- if (_cogl_texture_get_format (cogl_texture) == format)
+ if (!meta_multi_texture_is_simple (*texture) ||
+ _cogl_texture_get_format (cogl_texture) == cogl_format)
{
buffer->is_y_inverted = TRUE;
return TRUE;
@@ -309,41 +452,17 @@ shm_buffer_attach (MetaWaylandBuffer *buffer,
g_clear_object (texture);
wl_shm_buffer_begin_access (shm_buffer);
-
- bitmap = cogl_bitmap_new_for_data (cogl_context,
- width, height,
- format,
- stride,
- wl_shm_buffer_get_data (shm_buffer));
-
- new_cogl_tex = cogl_texture_2d_new_from_bitmap (bitmap);
-
- if (!cogl_texture_allocate (new_cogl_tex, error))
- {
- g_clear_object (&new_cogl_tex);
- if (g_error_matches (*error, COGL_TEXTURE_ERROR, COGL_TEXTURE_ERROR_SIZE))
- {
- g_clear_error (error);
-
- new_cogl_tex =
- cogl_texture_2d_sliced_new_from_bitmap (bitmap,
- COGL_TEXTURE_MAX_WASTE);
-
- if (!cogl_texture_allocate (new_cogl_tex, error))
- g_clear_object (&new_cogl_tex);
- }
- }
-
- g_object_unref (bitmap);
-
+ *texture = multi_texture_from_shm (cogl_context,
+ format_info,
+ width, height, stride,
+ wl_shm_buffer_get_data (shm_buffer),
+ error);
wl_shm_buffer_end_access (shm_buffer);
- if (!new_cogl_tex)
+ if (*texture == NULL)
return FALSE;
- *texture = meta_multi_texture_new_simple (new_cogl_tex);
buffer->is_y_inverted = TRUE;
-
return TRUE;
}
@@ -612,57 +731,82 @@ process_shm_buffer_damage (MetaWaylandBuffer *buffer,
MtkRegion *region,
GError **error)
{
+ const MetaFormatInfo *format_info;
+ MetaMultiTextureFormat multi_format;
+ const MetaMultiTextureFormatInfo *mt_format_info;
struct wl_shm_buffer *shm_buffer;
- int i, n_rectangles;
- gboolean set_texture_failed = FALSE;
- CoglPixelFormat format;
- CoglTexture *cogl_texture;
+ int shm_offset[3] = { 0 };
+ int shm_stride[3] = { 0 };
+ const uint8_t *data;
+ int stride;
+ int height;
uint32_t shm_format;
- const MetaFormatInfo *format_info;
+ int i, n_rectangles, n_planes;
n_rectangles = mtk_region_num_rectangles (region);
shm_buffer = wl_shm_buffer_get (buffer->resource);
-
+ stride = wl_shm_buffer_get_stride (shm_buffer);
+ height = wl_shm_buffer_get_height (shm_buffer);
shm_format = wl_shm_buffer_get_format (shm_buffer);
format_info = get_supported_shm_format_info (shm_format);
- g_assert (format_info != NULL);
- g_assert (format_info->multi_texture_format == META_MULTI_TEXTURE_FORMAT_SIMPLE);
- format = format_info->cogl_format;
+ multi_format = format_info->multi_texture_format;
+ mt_format_info = meta_multi_texture_format_get_info (multi_format);
+ n_planes = mt_format_info->n_planes;
- g_return_val_if_fail (cogl_pixel_format_get_n_planes (format) == 1, FALSE);
- cogl_texture = meta_multi_texture_get_plane (texture, 0);
+ get_offset_and_stride (format_info, stride, height, shm_offset, shm_stride);
wl_shm_buffer_begin_access (shm_buffer);
+ data = wl_shm_buffer_get_data (shm_buffer);
- for (i = 0; i < n_rectangles; i++)
+ for (i = 0; i < n_planes; i++)
{
- const uint8_t *data = wl_shm_buffer_get_data (shm_buffer);
- int32_t stride = wl_shm_buffer_get_stride (shm_buffer);
- MtkRectangle rect;
+ CoglTexture *cogl_texture;
+ int plane_index = mt_format_info->plane_indices[i];
+ int horizontal_factor = mt_format_info->hsub[i];
+ int vertical_factor = mt_format_info->vsub[i];
+ CoglPixelFormat subformat;
int bpp;
+ const uint8_t *plane_data;
+ size_t plane_stride;
+ int j;
+
+ plane_data = data + shm_offset[plane_index];
+ plane_stride = shm_stride[plane_index];
- bpp = cogl_pixel_format_get_bytes_per_pixel (format, 0);
- rect = mtk_region_get_rectangle (region, i);
-
- if (!_cogl_texture_set_region (cogl_texture,
- rect.width, rect.height,
- format,
- stride,
- data + rect.x * bpp + rect.y * stride,
- rect.x, rect.y,
- 0,
- error))
+ cogl_texture = meta_multi_texture_get_plane (texture, i);
+ subformat = _cogl_texture_get_format (cogl_texture);
+ bpp = cogl_pixel_format_get_bytes_per_pixel (subformat, 0);
+
+ for (j = 0; j < n_rectangles; j++)
{
- set_texture_failed = TRUE;
- break;
+ MtkRectangle rect;
+ const uint8_t *rect_data;
+
+ rect = mtk_region_get_rectangle (region, j);
+ rect_data = plane_data + (rect.x * bpp / horizontal_factor) +
+ (rect.y * plane_stride);
+
+ if (!_cogl_texture_set_region (cogl_texture,
+ rect.width / horizontal_factor,
+ rect.height / vertical_factor,
+ subformat,
+ plane_stride,
+ rect_data,
+ rect.x, rect.y,
+ 0,
+ error))
+ goto fail;
}
}
wl_shm_buffer_end_access (shm_buffer);
+ return TRUE;
- return !set_texture_failed;
+fail:
+ wl_shm_buffer_end_access (shm_buffer);
+ return FALSE;
}
void
@@ -907,6 +1051,10 @@ meta_wayland_init_shm (MetaWaylandCompositor *compositor)
WL_SHM_FORMAT_XRGB16161616F,
WL_SHM_FORMAT_ABGR16161616F,
WL_SHM_FORMAT_XBGR16161616F,
+ WL_SHM_FORMAT_YUYV,
+ WL_SHM_FORMAT_NV12,
+ WL_SHM_FORMAT_P010,
+ WL_SHM_FORMAT_YUV420,
};
wl_display_init_shm (compositor->wayland_display);