wayland/single-pixel-buffer: Use higher precision pixel formats

The single pixel buffer allows setting colors with 32 bpc.

Attempt to use pixel formats that allow higher precision than BGRA_8888.

First attempt to use half float format, fallback to ABGR_2101010 and
finally fallback to BGRA_8888.

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3913>
This commit is contained in:
Joan Torres 2024-07-30 12:23:53 +02:00 committed by Marge Bot
parent 3199d4bbb8
commit c05e3e74ac

View File

@ -21,6 +21,7 @@
#include "wayland/meta-wayland-single-pixel-buffer.h" #include "wayland/meta-wayland-single-pixel-buffer.h"
#include "backends/meta-backend-private.h" #include "backends/meta-backend-private.h"
#include "cogl/cogl-half-float.h"
#include "wayland/meta-wayland-buffer.h" #include "wayland/meta-wayland-buffer.h"
#include "wayland/meta-wayland-private.h" #include "wayland/meta-wayland-private.h"
@ -104,6 +105,77 @@ single_pixel_buffer_manager_bind (struct wl_client *client,
compositor, NULL); compositor, NULL);
} }
static void
get_data_in_half_float_format (MetaWaylandSinglePixelBuffer *single_pixel_buffer,
CoglPixelFormat *pixel_format,
int *rowstride,
uint8_t **data)
{
uint16_t *d;
if (single_pixel_buffer->a == UINT32_MAX)
*pixel_format = COGL_PIXEL_FORMAT_BGRX_FP_16161616;
else
*pixel_format = COGL_PIXEL_FORMAT_BGRA_FP_16161616_PRE;
*rowstride = 4 * sizeof (uint16_t);
d = g_malloc0 (*rowstride);
d[0] = cogl_float_to_half ((float) single_pixel_buffer->b / (float) UINT32_MAX);
d[1] = cogl_float_to_half ((float) single_pixel_buffer->g / (float) UINT32_MAX);
d[2] = cogl_float_to_half ((float) single_pixel_buffer->r / (float) UINT32_MAX);
d[3] = cogl_float_to_half ((float) single_pixel_buffer->a / (float) UINT32_MAX);
*data = (uint8_t *) d;
}
static void
get_data_in_ABGR_2101010_format (MetaWaylandSinglePixelBuffer *single_pixel_buffer,
CoglPixelFormat *pixel_format,
int *rowstride,
uint8_t **data)
{
uint32_t a, b, g, r;
uint32_t *d;
if (single_pixel_buffer->a == UINT32_MAX)
*pixel_format = COGL_PIXEL_FORMAT_XBGR_2101010;
else
*pixel_format = COGL_PIXEL_FORMAT_ABGR_2101010_PRE;
*rowstride = sizeof (uint32_t);
a = 3;
b = single_pixel_buffer->b / (UINT32_MAX / 0x3ff);
g = single_pixel_buffer->g / (UINT32_MAX / 0x3ff);
r = single_pixel_buffer->r / (UINT32_MAX / 0x3ff);
d = g_malloc0 (*rowstride);
*d = (a << 30) | (b << 20) | (g << 10) | r;
*data = (uint8_t *) d;
}
static void
get_data_in_BGRA_8888_format (MetaWaylandSinglePixelBuffer *single_pixel_buffer,
CoglPixelFormat *pixel_format,
int *rowstride,
uint8_t **data)
{
if (single_pixel_buffer->a == UINT32_MAX)
*pixel_format = COGL_PIXEL_FORMAT_BGR_888;
else
*pixel_format = COGL_PIXEL_FORMAT_BGRA_8888_PRE;
*rowstride = 4 * sizeof (uint8_t);
*data = g_malloc0 (*rowstride);
(*data)[0] = single_pixel_buffer->b / (UINT32_MAX / 0xff);
(*data)[1] = single_pixel_buffer->g / (UINT32_MAX / 0xff);
(*data)[2] = single_pixel_buffer->r / (UINT32_MAX / 0xff);
(*data)[3] = single_pixel_buffer->a / (UINT32_MAX / 0xff);
}
gboolean gboolean
meta_wayland_single_pixel_buffer_attach (MetaWaylandBuffer *buffer, meta_wayland_single_pixel_buffer_attach (MetaWaylandBuffer *buffer,
MetaMultiTexture **texture, MetaMultiTexture **texture,
@ -117,9 +189,10 @@ meta_wayland_single_pixel_buffer_attach (MetaWaylandBuffer *buffer,
clutter_backend_get_cogl_context (clutter_backend); clutter_backend_get_cogl_context (clutter_backend);
MetaWaylandSinglePixelBuffer *single_pixel_buffer = MetaWaylandSinglePixelBuffer *single_pixel_buffer =
wl_resource_get_user_data (buffer->resource); wl_resource_get_user_data (buffer->resource);
uint8_t data[4]; g_autofree uint8_t *data = NULL;
CoglPixelFormat pixel_format; CoglPixelFormat pixel_format;
CoglTexture *tex_2d; CoglTexture *tex_2d;
int rowstride;
if (buffer->single_pixel.texture) if (buffer->single_pixel.texture)
{ {
@ -127,20 +200,33 @@ meta_wayland_single_pixel_buffer_attach (MetaWaylandBuffer *buffer,
return TRUE; return TRUE;
} }
data[0] = single_pixel_buffer->b / (UINT32_MAX / 0xff); if (cogl_context_has_feature (cogl_context, COGL_FEATURE_ID_TEXTURE_HALF_FLOAT))
data[1] = single_pixel_buffer->g / (UINT32_MAX / 0xff); {
data[2] = single_pixel_buffer->r / (UINT32_MAX / 0xff); get_data_in_half_float_format (single_pixel_buffer,
data[3] = single_pixel_buffer->a / (UINT32_MAX / 0xff); &pixel_format,
&rowstride,
if (data[3] == UINT8_MAX) &data);
pixel_format = COGL_PIXEL_FORMAT_BGR_888; }
else if (cogl_context_has_feature (cogl_context, COGL_FEATURE_ID_TEXTURE_RGBA1010102) &&
single_pixel_buffer->a == UINT32_MAX)
{
get_data_in_ABGR_2101010_format (single_pixel_buffer,
&pixel_format,
&rowstride,
&data);
}
else else
pixel_format = COGL_PIXEL_FORMAT_BGRA_8888_PRE; {
get_data_in_BGRA_8888_format (single_pixel_buffer,
&pixel_format,
&rowstride,
&data);
}
tex_2d = cogl_texture_2d_new_from_data (cogl_context, tex_2d = cogl_texture_2d_new_from_data (cogl_context,
1, 1, 1, 1,
pixel_format, pixel_format,
4, data, rowstride, data,
error); error);
if (!tex_2d) if (!tex_2d)
return FALSE; return FALSE;