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);