From ff3b8197fd1b41d163d85f69aa9930b5d57ffb44 Mon Sep 17 00:00:00 2001 From: Sebastian Wick Date: Wed, 13 Dec 2023 15:00:35 +0100 Subject: [PATCH 01/11] tests/wayland-test-clients: Use ARGB dma-buf format for YUYV buffers They are the same for our purposes of allocating a linear buffer and writing to the CPU mapping, but the ARGB format is widely supported and the YUYV format is not. Part-of: --- .../wayland-test-clients/wayland-test-client-utils.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) 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 7c36fa5cb07..a579dce1049 100644 --- a/src/tests/wayland-test-clients/wayland-test-client-utils.c +++ b/src/tests/wayland-test-clients/wayland-test-client-utils.c @@ -1115,6 +1115,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; @@ -1249,8 +1255,8 @@ wayland_buffer_dmabuf_allocate (WaylandBuffer *buffer, { 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_YUYV: case DRM_FORMAT_NV12: case DRM_FORMAT_P010: case DRM_FORMAT_YUV420: -- GitLab From 628f12a48bb4f82405d7a38ad661e5abeb84172d Mon Sep 17 00:00:00 2001 From: Sebastian Wick Date: Wed, 13 Dec 2023 16:21:34 +0100 Subject: [PATCH 02/11] tests/wayland-test-clients: Try simple dma-buf alloc first and fall back to the complex one. If a driver supports allocating linear YCbCr formats we can use that instead of constructing our own compatible buffer. Part-of: --- .../wayland-test-client-utils.c | 28 +++++++------------ 1 file changed, 10 insertions(+), 18 deletions(-) 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 a579dce1049..c0bbc796bc9 100644 --- a/src/tests/wayland-test-clients/wayland-test-client-utils.c +++ b/src/tests/wayland-test-clients/wayland-test-client-utils.c @@ -1097,8 +1097,8 @@ alloc_dmabuf_simple (WaylandBuffer *buffer, } 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); @@ -1151,6 +1151,8 @@ alloc_dmabuf_ycbcr (WaylandBuffer *buffer, vsub[1] = 2; hsub[2] = 2; break; + default: + return FALSE; } wl_params = zwp_linux_dmabuf_v1_create_params (wl_dmabuf); @@ -1240,6 +1242,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++) { @@ -1251,23 +1256,10 @@ wayland_buffer_dmabuf_allocate (WaylandBuffer *buffer, } } - switch (priv->format) - { - case DRM_FORMAT_ARGB8888: - case DRM_FORMAT_XRGB8888: - return alloc_dmabuf_simple (buffer, n_modifiers, modifiers, bo_flags); - case DRM_FORMAT_YUYV: - 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 * -- GitLab From 0930282baa975efccf86f3d95cbebc0f575addd3 Mon Sep 17 00:00:00 2001 From: Sebastian Wick Date: Thu, 14 Dec 2023 16:08:54 +0100 Subject: [PATCH 03/11] tests/wayland-test-clients: Destroy WaylandBuffers when released Instead of forcing every user of WaylandBuffer to create a listener and destroy the wl_resource and the WaylandBuffer object, provide a default listener which does it for the user. Part-of: --- .../wayland-test-client-utils.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) 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 c0bbc796bc9..132e8d95678 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); -- GitLab From 005ede7702c4402397f4bf53349d18ddcc7b03ca Mon Sep 17 00:00:00 2001 From: Sebastian Wick Date: Wed, 13 Dec 2023 23:03:34 +0100 Subject: [PATCH 04/11] tests/wayland-test-clients: Fix YUV420 vertical subsampling factor Part-of: --- src/tests/wayland-test-clients/wayland-test-client-utils.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 132e8d95678..23f56933782 100644 --- a/src/tests/wayland-test-clients/wayland-test-client-utils.c +++ b/src/tests/wayland-test-clients/wayland-test-client-utils.c @@ -932,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 (); @@ -1166,7 +1166,7 @@ alloc_dmabuf_complex (WaylandBuffer *buffer, hsub[2] = 2; vsub[0] = 1; vsub[1] = 2; - hsub[2] = 2; + vsub[2] = 2; break; default: return FALSE; -- GitLab From 5652c61c069e87bad14467eb4509840b6b55bc8a Mon Sep 17 00:00:00 2001 From: Sebastian Wick Date: Wed, 13 Dec 2023 18:56:43 +0100 Subject: [PATCH 05/11] tests/wayland-test-clients: Use stride of the first plane The assumption is that all planes are always contiguous, and we don't have any multi-plane formats where the first plane is subsampled. The stride of the entire buffer is then just the stride of the first plane and the stride of the other planes is derived from that. Part-of: --- src/tests/wayland-test-clients/wayland-test-client-utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 23f56933782..1a8e38eea2d 100644 --- a/src/tests/wayland-test-clients/wayland-test-client-utils.c +++ b/src/tests/wayland-test-clients/wayland-test-client-utils.c @@ -973,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); -- GitLab From 19472c75be5ff07122edfb9659e7544dfa3d6408 Mon Sep 17 00:00:00 2001 From: Sebastian Wick Date: Thu, 14 Dec 2023 16:57:37 +0100 Subject: [PATCH 06/11] tests/wayland-test-clients: Fix up whitespace Part-of: --- .../wayland-test-client-utils.c | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) 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 1a8e38eea2d..e560a03b0ba 100644 --- a/src/tests/wayland-test-clients/wayland-test-client-utils.c +++ b/src/tests/wayland-test-clients/wayland-test-client-utils.c @@ -1103,11 +1103,11 @@ 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; @@ -1233,11 +1233,11 @@ alloc_dmabuf_complex (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; -- GitLab From e40a256584f263e3bf3b6a87dabef68f701055c7 Mon Sep 17 00:00:00 2001 From: Sebastian Wick Date: Tue, 31 Oct 2023 16:34:48 +0100 Subject: [PATCH 07/11] cogl/pixel-format: Support 16 bpc UNORM formats Part-of: --- cogl/cogl/cogl-bitmap-conversion.c | 15 ++- cogl/cogl/cogl-bitmap-packing.h | 122 ++++++++++++++++++ cogl/cogl/cogl-context.h | 2 + cogl/cogl/cogl-pixel-format.c | 16 ++- cogl/cogl/cogl-pixel-format.h | 14 +- cogl/cogl/driver/gl/gl/cogl-driver-gl.c | 21 ++- .../driver/gl/gl/cogl-texture-driver-gl.c | 4 +- cogl/cogl/driver/gl/gles/cogl-driver-gles.c | 80 +++++++++++- .../driver/gl/gles/cogl-texture-driver-gles.c | 7 + 9 files changed, 265 insertions(+), 16 deletions(-) diff --git a/cogl/cogl/cogl-bitmap-conversion.c b/cogl/cogl/cogl-bitmap-conversion.c index eafff004a15..76efbb9bb9b 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 b824d863710..720fe06f31d 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 e0e37961cb3..e760afafe02 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 94727726876..3b28df68d37 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 9417794e07c..7995ae0173d 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 174f233afad..a8407b767ae 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 ea0243017a5..dd19d956bf2 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 e9a2002414c..3cb8ab05fc4 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 4b6d8742699..72d8155d0ef 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: -- GitLab From a4d75e82528ea0e5eca3602519c8b720398d9e41 Mon Sep 17 00:00:00 2001 From: Sebastian Wick Date: Tue, 31 Oct 2023 19:08:06 +0100 Subject: [PATCH 08/11] cogl/test: Test 16bpc RGBA UNORM formats Part-of: --- .../conform/test-offscreen-texture-formats.c | 104 ++++++++++++++++++ 1 file changed, 104 insertions(+) diff --git a/src/tests/cogl/conform/test-offscreen-texture-formats.c b/src/tests/cogl/conform/test-offscreen-texture-formats.c index 0ecc35a6acb..c15194a4d1f 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", -- GitLab From c8f4c85bfb8d97d5159baaab13caf32c47d311a2 Mon Sep 17 00:00:00 2001 From: Sebastian Wick Date: Tue, 31 Oct 2023 13:35:03 +0100 Subject: [PATCH 09/11] wayland-buffer: Support MultiTexture formats via wayland shm Finding the shm offset and shm stride for each plane is the main issue. The rest is just creating multiple textures for each plane. One assumption is that shm planes are always contiguous in memory so the next plane comes directly after the size of the current plane. The size of a plane is determined by the height and stride. There is only a single stride parameter for shm buffers but we assume that the first plane is always non-subsampled which gives us a number of "logical elements" on one line (stride / bpp of the first plane). The stride of the other planes is then the number of logical elements devided by the subsampling factor and multiplied by the bpp of the plane. Part-of: --- src/wayland/meta-wayland-buffer.c | 280 ++++++++++++++++++++++-------- 1 file changed, 212 insertions(+), 68 deletions(-) diff --git a/src/wayland/meta-wayland-buffer.c b/src/wayland/meta-wayland-buffer.c index 0fd1aee6cdf..7e81f38bb9a 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 -- GitLab From 59d4343057f707f06fe8fec7b039c11b07af985f Mon Sep 17 00:00:00 2001 From: Sebastian Wick Date: Tue, 7 Nov 2023 14:55:11 +0100 Subject: [PATCH 10/11] wayland-buffer: Enable YCbCr support for wayland shm Part-of: --- src/wayland/meta-wayland-buffer.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/wayland/meta-wayland-buffer.c b/src/wayland/meta-wayland-buffer.c index 7e81f38bb9a..40386ad79ed 100644 --- a/src/wayland/meta-wayland-buffer.c +++ b/src/wayland/meta-wayland-buffer.c @@ -1051,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); -- GitLab From 4c6216e8a33118ae5afabc34b9bb793375409dae Mon Sep 17 00:00:00 2001 From: Sebastian Wick Date: Mon, 13 Nov 2023 14:36:50 +0100 Subject: [PATCH 11/11] tests/wayland: Add basic YCbCr ref-tests The test makes sure the YCbCr formats create the expected image and we don't accidentally break it. Like all wayland tests, this is now part of mutter/wayland, mutter/tty, and mutter/kvm and will use either shm or dma-buf depending on which suite is chosen. Part-of: --- src/tests/meson.build | 1 + .../wayland_buffer_ycbcr-basic_0.ref.png | Bin 0 -> 1478 bytes .../wayland_buffer_ycbcr-basic_1.ref.png | Bin 0 -> 1516 bytes .../wayland_buffer_ycbcr-basic_2.ref.png | Bin 0 -> 1478 bytes .../wayland_buffer_ycbcr-basic_3.ref.png | Bin 0 -> 1392 bytes src/tests/wayland-test-clients/meson.build | 3 + src/tests/wayland-test-clients/ycbcr.c | 231 ++++++++++++++++++ src/tests/wayland-unit-tests.c | 12 + 8 files changed, 247 insertions(+) create mode 100644 src/tests/ref-tests/wayland_buffer_ycbcr-basic_0.ref.png create mode 100644 src/tests/ref-tests/wayland_buffer_ycbcr-basic_1.ref.png create mode 100644 src/tests/ref-tests/wayland_buffer_ycbcr-basic_2.ref.png create mode 100644 src/tests/ref-tests/wayland_buffer_ycbcr-basic_3.ref.png create mode 100644 src/tests/wayland-test-clients/ycbcr.c diff --git a/src/tests/meson.build b/src/tests/meson.build index fff12137da0..8eae7c64b3b 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 GIT binary patch literal 1478 zcmeAS@N?(olHy`uVBq!ia0y~yU}|7sV0^&A1Qgk|*?TjPVoUONcVYMsf(!O8pUl9( zTJ7oL7*a9k?JY+?X+{y2z#oTqPL{D%FE9&il)4wa(P2~SOaGI+`T0Q2qhMe|VD`QJ zzjzPyfB9GTz3%&+;`4X^|M}2=|3}5V|23WW_y4Q;s?K`N;`)WjR(^sSFh)k3S#1!pR{3LdQ;mZ=H`28wdYxQ zRoU4#-uz{!mZ8CEFlE~7Y9PbXfW!CtbrxPtcD98tf6ZE;sCqzP*1GpI7c6{oK*1z7 zUf5)bj6}<_*V#>NQy82xc0tX%P*UrAVM0*?P%XqNpyqj;QeJ#KPM5!$Iy#?fbOfqZ z%kbbd0BU|MZ2&Rl_s56Q1}!WSKt;B~CQ~4c|EwT~0S&PG$HoI;(a0T?c^DFaAa{ZT z5a=(;%)=dkw&&SF5wlYNLzi^(gkMbSEsVh&ZwSW>%&CTOEWw=B5RMIyGqCA+)OKJ9 ce7O6E^;c3sFVdQ&MBb@09d&*OaK4? literal 0 HcmV?d00001 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 GIT binary patch literal 1516 zcmeAS@N?(olHy`uVBq!ia0y~yU}|7sV0^&A1Qgk|*?TjPVoUONcVYMsf(!O8pUl9( zy3o_bF{EP7+dGbV!j1xM7yDWoR22%f&YgbCk@)be!s<1JbN25}`*ZJ5_mQr&ss5o) zQ+R;pjDi6TfrjL&$iEB)Y5VWh^%)-fv90oN-PftFzJ59ER?|UYtt{rhHWeoO+E)4TpJWU8XCJ8oF|By1PCT@7%?)7GPWrQ8z6BQ z*|eB=9K$Yv6rW(>2?6S4kyycDz!K?*sTiVDC}Dxp0f7`&UXWslHBg=V*3~gA&;?qd zodHs!0(Qa)Ua)zx6-;%pK;M)Bt!wA`@cNl(2hd4YH@K>1-?P`2XPMW?;Cvxb?Llsd z?*W5WhQr0X`_?fW7GdH!|2(%R&^^2%k&Ce{eUts(yaNJi2R_JrTXLOOLQN>aV)yNr zrOa)vEE4Bdd%b`Ag3G{1@j!vw^_O?$W6cw0I5j+s+4izF9%^djoBu7Fr439J4iwaU zUj{TmN+7{v)8FlJ<_Q^Y4G(90yHjq^hN@rF*cfZcU6U<@orMUW`&GX0MOgxE9 zJacXAPS?GWS7S6};<0^l?L^*z3zHZQXYDlI1ayYlfeq*8fLL2p4s39;+69!H$8b32 z^L3~)9SCa%gY&&xP-PRgXhD=Y2eq4iQvS#WbkHQZ^Q)u{=1gG#i9t-8@Pv&=1Sn&* zW+Ko-s*G(a<_QZF4otX`*!zZ!N0-w;C0BX-xA|UN1_PSJM=b}1zz4;DjGVTth1prN Pia~r&S3j3^P6N;`)WjR(^sSFh)k3S#1!pR{3LdQ;mZ=H`28wdYxQ zRoU4#-uz{!mZ8CEFlE~7Y9PbXfW!CtbrxPtcD98tf6ZE;sCqzP*1GpI7c6{oK*1z7 zUf5)bj6}<_*V#>NQy82xc0tX%P*UrAVM0*?P%XqNpyqj;QeJ#KPM5!$Iy#?fbOfqZ z%kbbd0BU|MZ2&Rl_s56Q1}!WSKt;B~CQ~4c|EwT~0S&PG$HoI;(a0T?c^DFaAa{ZT z5a=(;%)=dkw&&SF5wlYNLzi^(gkMbSEsVh&ZwSW>%&CTOEWw=B5RMIyGqCA+)OKJ9 ce7O6E^;c3sFVdQ&MBb@09d&*OaK4? literal 0 HcmV?d00001 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 GIT binary patch literal 1392 zcmeAS@N?(olHy`uVBq!ia0y~yU}|7sV0^&A1Qgk|*?TjPVoUONcVYMsf(!O8pUl9( zs_ND%>=$X9{5L#xt)rsbAxTbo z>y;q$M!|rFz>Q_Azc6k{_m{6$tDDImp76vcC5TT8VL*>0S7K*OrGCVw|>>C z?H@!pR717h@?q3p{ry8t?_DNwC#VJHFPZlh$Lu}*Z7ZX*F~okolNqmNOARi#L6q#Z z4tc+#B=>;8q6S6<2gbv4YggVgUC)#Y@x+bpucz1XN~kS>NKTs@wAU=5BM9u*#B8go z>ufyf%OP@i>{h+nb9HwOOzVvEg. + */ + +#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 aff7515a854..c9f3f32e3f3 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", -- GitLab