mirror of
https://gitlab.freedesktop.org/wayland/weston.git
synced 2026-01-03 17:30:20 +01:00
Merge branch 'color-representation-implementation' into 'main'
libweston: Implement color-representation protocol See merge request wayland/weston!1682
This commit is contained in:
commit
a673e25f79
26 changed files with 2107 additions and 90 deletions
|
|
@ -43,7 +43,7 @@
|
|||
variables:
|
||||
FDO_UPSTREAM_REPO: wayland/weston
|
||||
FDO_REPO_SUFFIX: "$BUILD_OS-$FDO_DISTRIBUTION_VERSION/$BUILD_ARCH"
|
||||
FDO_DISTRIBUTION_TAG: '2025-12-16-bump-to-trixie'
|
||||
FDO_DISTRIBUTION_TAG: '2025-12-16-wayland-protocols-1.46'
|
||||
|
||||
|
||||
include:
|
||||
|
|
|
|||
|
|
@ -117,7 +117,7 @@ rm -rf wayland
|
|||
# Keep this version in sync with our dependency in meson.build. If you wish to
|
||||
# raise a MR against custom protocol, please change this reference to clone
|
||||
# your relevant tree, and make sure you bump $FDO_DISTRIBUTION_TAG.
|
||||
git clone --branch 1.44 --depth=1 https://gitlab.freedesktop.org/wayland/wayland-protocols
|
||||
git clone --branch 1.46 --depth=1 https://gitlab.freedesktop.org/wayland/wayland-protocols
|
||||
cd wayland-protocols
|
||||
git show -s HEAD
|
||||
meson setup build --wrap-mode=nofallback -Dtests=false
|
||||
|
|
|
|||
|
|
@ -886,6 +886,7 @@ static const struct {
|
|||
{ WESTON_CAP_VIEW_CLIP_MASK, "view mask clipping" },
|
||||
{ WESTON_CAP_EXPLICIT_SYNC, "explicit sync" },
|
||||
{ WESTON_CAP_COLOR_OPS, "color operations" },
|
||||
{ WESTON_CAP_COLOR_REP, "color representation" }
|
||||
};
|
||||
|
||||
static void
|
||||
|
|
|
|||
|
|
@ -187,6 +187,36 @@ enum weston_transfer_function {
|
|||
WESTON_TF_POWER,
|
||||
};
|
||||
|
||||
enum weston_alpha_mode {
|
||||
WESTON_ALPHA_MODE_PREMULTIPLIED_ELECTRICAL = 0,
|
||||
WESTON_ALPHA_MODE_PREMULTIPLIED_OPTICAL,
|
||||
WESTON_ALPHA_MODE_STRAIGHT,
|
||||
};
|
||||
|
||||
enum weston_color_matrix_coef {
|
||||
WESTON_COLOR_MATRIX_COEF_UNSET = 0,
|
||||
WESTON_COLOR_MATRIX_COEF_IDENTITY,
|
||||
WESTON_COLOR_MATRIX_COEF_BT601,
|
||||
WESTON_COLOR_MATRIX_COEF_BT709,
|
||||
WESTON_COLOR_MATRIX_COEF_BT2020,
|
||||
};
|
||||
|
||||
enum weston_color_quant_range {
|
||||
WESTON_COLOR_QUANT_RANGE_UNSET = 0,
|
||||
WESTON_COLOR_QUANT_RANGE_FULL,
|
||||
WESTON_COLOR_QUANT_RANGE_LIMITED,
|
||||
};
|
||||
|
||||
enum weston_ycbcr_chroma_location {
|
||||
WESTON_YCBCR_CHROMA_LOCATION_UNSET = 0,
|
||||
WESTON_YCBCR_CHROMA_LOCATION_TYPE_0,
|
||||
WESTON_YCBCR_CHROMA_LOCATION_TYPE_1,
|
||||
WESTON_YCBCR_CHROMA_LOCATION_TYPE_2,
|
||||
WESTON_YCBCR_CHROMA_LOCATION_TYPE_3,
|
||||
WESTON_YCBCR_CHROMA_LOCATION_TYPE_4,
|
||||
WESTON_YCBCR_CHROMA_LOCATION_TYPE_5,
|
||||
};
|
||||
|
||||
/** Error codes that the color profile parameters functions may return. */
|
||||
enum weston_color_profile_param_builder_error {
|
||||
WESTON_COLOR_PROFILE_PARAM_BUILDER_ERROR_INVALID_TF = 0,
|
||||
|
|
|
|||
|
|
@ -921,6 +921,18 @@ struct weston_tablet {
|
|||
const char *path;
|
||||
};
|
||||
|
||||
struct weston_color_representation {
|
||||
enum weston_alpha_mode alpha_mode;
|
||||
enum weston_color_matrix_coef matrix_coefficients;
|
||||
enum weston_color_quant_range quant_range;
|
||||
enum weston_ycbcr_chroma_location chroma_location;
|
||||
};
|
||||
|
||||
struct weston_color_representation_matrix {
|
||||
struct weston_mat3f matrix;
|
||||
struct weston_vec3f offset;
|
||||
};
|
||||
|
||||
struct weston_coord_global
|
||||
weston_pointer_motion_to_abs(struct weston_pointer *pointer,
|
||||
struct weston_pointer_motion_event *event);
|
||||
|
|
@ -1278,6 +1290,9 @@ enum weston_capability {
|
|||
|
||||
/* renderer supports color management operations */
|
||||
WESTON_CAP_COLOR_OPS = 0x0040,
|
||||
|
||||
/* renderer supports color representation operations */
|
||||
WESTON_CAP_COLOR_REP = 0x0080,
|
||||
};
|
||||
|
||||
/* Configuration struct for a backend.
|
||||
|
|
@ -1826,6 +1841,11 @@ struct weston_surface_state {
|
|||
struct weston_color_profile *color_profile;
|
||||
const struct weston_render_intent_info *render_intent;
|
||||
|
||||
/* wp_color_representation_surface_v1.set_alpha_mode */
|
||||
/* wp_color_representation_surface_v1.set_coefficients_and_range */
|
||||
/* wp_color_representation_surface_v1.set_chroma_location */
|
||||
struct weston_color_representation color_representation;
|
||||
|
||||
/* wp_fifo_v1 */
|
||||
bool fifo_barrier;
|
||||
bool fifo_wait;
|
||||
|
|
@ -1990,6 +2010,9 @@ struct weston_surface {
|
|||
struct wl_list cm_surface_feedback_resource_list;
|
||||
struct wl_resource *cm_surface;
|
||||
|
||||
struct wl_resource *color_representation_resource;
|
||||
struct weston_color_representation color_representation;
|
||||
|
||||
uint64_t damage_track_id;
|
||||
uint64_t flow_id;
|
||||
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@
|
|||
#include "drm-internal.h"
|
||||
|
||||
#include "color.h"
|
||||
#include "color-representation.h"
|
||||
#include "linux-dmabuf.h"
|
||||
#include "presentation-time-server-protocol.h"
|
||||
#include "linux-dmabuf-unstable-v1-server-protocol.h"
|
||||
|
|
@ -139,23 +140,33 @@ drm_output_try_paint_node_on_plane(struct drm_plane *plane,
|
|||
state->in_fence_fd = ev->surface->acquire_fence_fd;
|
||||
|
||||
if (fb->format && fb->format->color_model == COLOR_MODEL_YUV) {
|
||||
enum wdrm_plane_color_encoding color_encoding;
|
||||
enum wdrm_plane_color_range color_range;
|
||||
struct weston_color_representation color_rep;
|
||||
const struct weston_color_matrix_coef_info *matrix_coef_info;
|
||||
const struct weston_color_quant_range_info *quant_range_info;
|
||||
|
||||
color_rep =
|
||||
weston_fill_color_representation(&surface->color_representation,
|
||||
fb->format);
|
||||
matrix_coef_info =
|
||||
weston_color_matrix_coef_info_get(color_rep.matrix_coefficients);
|
||||
assert(matrix_coef_info);
|
||||
assert(matrix_coef_info->wdrm != WDRM_PLANE_COLOR_ENCODING__COUNT);
|
||||
|
||||
quant_range_info =
|
||||
weston_color_quant_range_info_get(color_rep.quant_range);
|
||||
assert(quant_range_info);
|
||||
assert(quant_range_info->wdrm != WDRM_PLANE_COLOR_RANGE__COUNT);
|
||||
|
||||
/* These values will become dynamic once we implement the
|
||||
* color-representation protocol. */
|
||||
color_encoding = WDRM_PLANE_COLOR_ENCODING_DEFAULT;
|
||||
color_range = WDRM_PLANE_COLOR_RANGE_DEFAULT;
|
||||
|
||||
if (plane->props[WDRM_PLANE_COLOR_ENCODING].prop_id == 0) {
|
||||
if (color_encoding != WDRM_PLANE_COLOR_ENCODING_DEFAULT) {
|
||||
if (matrix_coef_info->wdrm != WDRM_PLANE_COLOR_ENCODING_DEFAULT) {
|
||||
drm_debug(b, "\t\t\t[view] not placing view %p on plane %lu: "
|
||||
"non-default color encoding not supported\n",
|
||||
ev, (unsigned long) plane->plane_id);
|
||||
goto out;
|
||||
}
|
||||
} else if (!drm_plane_supports_color_encoding(plane,
|
||||
color_encoding)) {
|
||||
matrix_coef_info->wdrm)) {
|
||||
drm_debug(b, "\t\t\t[view] not placing view %p on plane %lu: "
|
||||
"color encoding not supported\n", ev,
|
||||
(unsigned long) plane->plane_id);
|
||||
|
|
@ -163,22 +174,22 @@ drm_output_try_paint_node_on_plane(struct drm_plane *plane,
|
|||
}
|
||||
|
||||
if (plane->props[WDRM_PLANE_COLOR_RANGE].prop_id == 0) {
|
||||
if (color_range != WDRM_PLANE_COLOR_RANGE_DEFAULT) {
|
||||
if (quant_range_info->wdrm != WDRM_PLANE_COLOR_RANGE_DEFAULT) {
|
||||
drm_debug(b, "\t\t\t[view] not placing view %p on plane %lu: "
|
||||
"non-default color range not supported\n",
|
||||
ev, (unsigned long) plane->plane_id);
|
||||
goto out;
|
||||
}
|
||||
} else if (!drm_plane_supports_color_range(plane,
|
||||
color_range)) {
|
||||
quant_range_info->wdrm)) {
|
||||
drm_debug(b, "\t\t\t[view] not placing view %p on plane %lu: "
|
||||
"color range not supported\n", ev,
|
||||
(unsigned long) plane->plane_id);
|
||||
goto out;
|
||||
}
|
||||
|
||||
state->color_encoding = color_encoding;
|
||||
state->color_range = color_range;
|
||||
state->color_encoding = matrix_coef_info->wdrm;
|
||||
state->color_range = quant_range_info->wdrm;
|
||||
}
|
||||
|
||||
/* In planes-only mode, we don't have an incremental state to
|
||||
|
|
|
|||
554
libweston/color-representation.c
Normal file
554
libweston/color-representation.c
Normal file
|
|
@ -0,0 +1,554 @@
|
|||
/*
|
||||
* Copyright 2025 Collabora, Ltd.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the
|
||||
* next paragraph) shall be included in all copies or substantial
|
||||
* portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "color-representation.h"
|
||||
|
||||
#include "libweston-internal.h"
|
||||
#include "pixel-formats.h"
|
||||
#include "shared/string-helpers.h"
|
||||
#include "shared/weston-assert.h"
|
||||
#include "shared/xalloc.h"
|
||||
|
||||
#include "color-representation-v1-server-protocol.h"
|
||||
|
||||
static const enum wp_color_representation_surface_v1_alpha_mode supported_alpha_modes[] = {
|
||||
WP_COLOR_REPRESENTATION_SURFACE_V1_ALPHA_MODE_PREMULTIPLIED_ELECTRICAL,
|
||||
};
|
||||
|
||||
struct coeffs_and_range {
|
||||
enum wp_color_representation_surface_v1_coefficients coefficients;
|
||||
enum wp_color_representation_surface_v1_range range;
|
||||
};
|
||||
|
||||
#define CRS(x) WP_COLOR_REPRESENTATION_SURFACE_V1_ ##x
|
||||
static const struct coeffs_and_range supported_coeffs_and_ranges[] = {
|
||||
{ CRS(COEFFICIENTS_IDENTITY), CRS(RANGE_FULL) },
|
||||
{ CRS(COEFFICIENTS_BT601), CRS(RANGE_LIMITED) },
|
||||
{ CRS(COEFFICIENTS_BT601), CRS(RANGE_FULL) },
|
||||
{ CRS(COEFFICIENTS_BT709), CRS(RANGE_LIMITED) },
|
||||
{ CRS(COEFFICIENTS_BT709), CRS(RANGE_FULL) },
|
||||
{ CRS(COEFFICIENTS_BT2020), CRS(RANGE_LIMITED) },
|
||||
{ CRS(COEFFICIENTS_BT2020), CRS(RANGE_FULL) },
|
||||
};
|
||||
#undef CRS
|
||||
|
||||
WL_EXPORT void
|
||||
weston_reset_color_representation(struct weston_color_representation *color_rep)
|
||||
{
|
||||
color_rep->alpha_mode = WESTON_ALPHA_MODE_PREMULTIPLIED_ELECTRICAL;
|
||||
color_rep->matrix_coefficients = WESTON_COLOR_MATRIX_COEF_UNSET;
|
||||
color_rep->quant_range = WESTON_COLOR_QUANT_RANGE_UNSET;
|
||||
color_rep->chroma_location = WESTON_YCBCR_CHROMA_LOCATION_UNSET;
|
||||
}
|
||||
|
||||
WL_EXPORT struct weston_color_representation
|
||||
weston_fill_color_representation(const struct weston_color_representation *color_rep_in,
|
||||
const struct pixel_format_info *info)
|
||||
{
|
||||
struct weston_color_representation color_rep;
|
||||
|
||||
color_rep = *color_rep_in;
|
||||
|
||||
if (color_rep.matrix_coefficients == WESTON_COLOR_MATRIX_COEF_UNSET) {
|
||||
if (info->color_model == COLOR_MODEL_YUV)
|
||||
color_rep.matrix_coefficients =
|
||||
WESTON_COLOR_MATRIX_COEF_BT709;
|
||||
else
|
||||
color_rep.matrix_coefficients =
|
||||
WESTON_COLOR_MATRIX_COEF_IDENTITY;
|
||||
}
|
||||
if (color_rep.quant_range == WESTON_COLOR_QUANT_RANGE_UNSET) {
|
||||
if (info->color_model == COLOR_MODEL_YUV)
|
||||
color_rep.quant_range = WESTON_COLOR_QUANT_RANGE_LIMITED;
|
||||
else
|
||||
color_rep.quant_range = WESTON_COLOR_QUANT_RANGE_FULL;
|
||||
}
|
||||
|
||||
return color_rep;
|
||||
}
|
||||
|
||||
|
||||
WL_EXPORT bool
|
||||
weston_color_representation_equal(struct weston_color_representation *color_rep_A,
|
||||
struct weston_color_representation *color_rep_B,
|
||||
enum weston_cr_comparison_flag flags)
|
||||
{
|
||||
if (!(flags & WESTON_CR_COMPARISON_FLAG_IGNORE_ALPHA) &&
|
||||
color_rep_A->alpha_mode != color_rep_B->alpha_mode)
|
||||
return false;
|
||||
|
||||
if (!(flags & WESTON_CR_COMPARISON_FLAG_IGNORE_CHROMA_LOCATION) &&
|
||||
color_rep_A->chroma_location != color_rep_B->chroma_location)
|
||||
return false;
|
||||
|
||||
return (color_rep_A->matrix_coefficients == color_rep_B->matrix_coefficients &&
|
||||
color_rep_A->quant_range == color_rep_B->quant_range);
|
||||
}
|
||||
|
||||
WL_EXPORT void
|
||||
weston_get_color_representation_matrix(struct weston_compositor *compositor,
|
||||
enum weston_color_matrix_coef coefficients,
|
||||
enum weston_color_quant_range range,
|
||||
struct weston_color_representation_matrix *cr_matrix)
|
||||
{
|
||||
/* The values in this function are copied from Mesa and may not be
|
||||
* optimal or correct in all cases. */
|
||||
|
||||
if (range == WESTON_COLOR_QUANT_RANGE_FULL) {
|
||||
cr_matrix->offset =
|
||||
WESTON_VEC3F(0.0, 128.0 / 255.0, 128.0 / 255.0);
|
||||
|
||||
switch(coefficients) {
|
||||
case WESTON_COLOR_MATRIX_COEF_BT601:
|
||||
cr_matrix->matrix =
|
||||
WESTON_MAT3F(1.0, 0.0, 1.402,
|
||||
1.0, -0.34413629, -0.71413629,
|
||||
1.0, 1.772, 0.0);
|
||||
return;
|
||||
case WESTON_COLOR_MATRIX_COEF_BT709:
|
||||
cr_matrix->matrix =
|
||||
WESTON_MAT3F(1.0, 0.0, 1.5748,
|
||||
1.0, -0.18732427, -0.46812427,
|
||||
1.0, 1.8556, 0.0);
|
||||
return;
|
||||
case WESTON_COLOR_MATRIX_COEF_BT2020:
|
||||
cr_matrix->matrix =
|
||||
WESTON_MAT3F(1.0, 0.0, 1.4746,
|
||||
1.0, -0.16455313, -0.57139187,
|
||||
1.0, 1.8814, 0.0);
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if (range == WESTON_COLOR_QUANT_RANGE_LIMITED) {
|
||||
cr_matrix->offset =
|
||||
WESTON_VEC3F(16.0 / 255.0, 128.0 / 255.0, 128.0 / 255.0);
|
||||
|
||||
switch(coefficients) {
|
||||
case WESTON_COLOR_MATRIX_COEF_BT601:
|
||||
cr_matrix->matrix =
|
||||
WESTON_MAT3F(255.0 / 219.0, 0.0, 1.59602678,
|
||||
255.0 / 219.0, -0.39176229, -0.81296764,
|
||||
255.0 / 219.0, 2.01723214, 0.0);
|
||||
return;
|
||||
case WESTON_COLOR_MATRIX_COEF_BT709:
|
||||
cr_matrix->matrix =
|
||||
WESTON_MAT3F(255.0 / 219.0, 0.0, 1.79274107,
|
||||
255.0 / 219.0, -0.21324861, -0.53290933,
|
||||
255.0 / 219.0, 2.11240179, 0.0);
|
||||
return;
|
||||
case WESTON_COLOR_MATRIX_COEF_BT2020:
|
||||
cr_matrix->matrix =
|
||||
WESTON_MAT3F(255.0 / 219.0, 0.0, 1.67878795,
|
||||
255.0 / 219.0, -0.18732610, -0.65046843,
|
||||
255.0 / 219.0, 2.14177232, 0.0);
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
weston_assert_not_reached(compositor,
|
||||
"unknown coefficients or range value");
|
||||
}
|
||||
|
||||
bool
|
||||
weston_surface_check_pending_color_representation_valid(
|
||||
const struct weston_surface *surface)
|
||||
{
|
||||
const struct weston_surface_state *pend = &surface->pending;
|
||||
const struct weston_color_representation *cr =
|
||||
&pend->color_representation;
|
||||
struct weston_buffer *buffer = NULL;
|
||||
bool format_is_yuv;
|
||||
|
||||
if (!surface->color_representation_resource)
|
||||
return true;
|
||||
|
||||
if (cr->matrix_coefficients == WESTON_COLOR_MATRIX_COEF_UNSET &&
|
||||
cr->quant_range == WESTON_COLOR_QUANT_RANGE_UNSET)
|
||||
return true;
|
||||
|
||||
assert(cr->matrix_coefficients != WESTON_COLOR_MATRIX_COEF_UNSET &&
|
||||
cr->quant_range != WESTON_COLOR_QUANT_RANGE_UNSET);
|
||||
|
||||
if (pend->status & WESTON_SURFACE_DIRTY_BUFFER) {
|
||||
buffer = pend->buffer_ref.buffer;
|
||||
} else if (surface->buffer_ref.buffer) {
|
||||
buffer = surface->buffer_ref.buffer;
|
||||
}
|
||||
|
||||
if (!buffer)
|
||||
return true;
|
||||
|
||||
format_is_yuv = buffer->pixel_format->color_model == COLOR_MODEL_YUV;
|
||||
if ((format_is_yuv &&
|
||||
cr->matrix_coefficients == WESTON_COLOR_MATRIX_COEF_IDENTITY) ||
|
||||
(!format_is_yuv &&
|
||||
cr->matrix_coefficients != WESTON_COLOR_MATRIX_COEF_IDENTITY)) {
|
||||
wl_resource_post_error(surface->color_representation_resource,
|
||||
WP_COLOR_REPRESENTATION_SURFACE_V1_ERROR_PIXEL_FORMAT,
|
||||
"wp_color_representation_surface_v1@%"PRIu32" "
|
||||
"Buffer format %s not compatible "
|
||||
"with matrix coefficients %u",
|
||||
wl_resource_get_id(surface->resource),
|
||||
buffer->pixel_format->drm_format_name,
|
||||
cr->matrix_coefficients);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
destroy_color_representation(struct wl_resource *resource)
|
||||
{
|
||||
struct weston_surface *surface =
|
||||
wl_resource_get_user_data(resource);
|
||||
|
||||
if (!surface)
|
||||
return;
|
||||
|
||||
surface->color_representation_resource = NULL;
|
||||
weston_reset_color_representation(&surface->pending.color_representation);
|
||||
}
|
||||
|
||||
static void
|
||||
cr_destroy(struct wl_client *client,
|
||||
struct wl_resource *resource)
|
||||
{
|
||||
wl_resource_destroy(resource);
|
||||
}
|
||||
|
||||
static void
|
||||
cr_set_alpha_mode(struct wl_client *client,
|
||||
struct wl_resource *resource,
|
||||
uint32_t alpha_mode)
|
||||
{
|
||||
struct weston_surface *surface =
|
||||
wl_resource_get_user_data(resource);
|
||||
bool supported = false;
|
||||
|
||||
if (!surface) {
|
||||
wl_resource_post_error(resource,
|
||||
WP_COLOR_REPRESENTATION_SURFACE_V1_ERROR_INERT,
|
||||
"wp_color_representation_surface_v1@%"PRIu32" "
|
||||
"The object is inert.",
|
||||
wl_resource_get_id(resource));
|
||||
return;
|
||||
}
|
||||
|
||||
weston_assert_ptr_eq(surface->compositor,
|
||||
surface->color_representation_resource, resource);
|
||||
|
||||
for (unsigned int i = 0; i < ARRAY_LENGTH(supported_alpha_modes); i++) {
|
||||
if (supported_alpha_modes[i] == alpha_mode) {
|
||||
supported = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!supported) {
|
||||
wl_resource_post_error(resource,
|
||||
WP_COLOR_REPRESENTATION_SURFACE_V1_ERROR_ALPHA_MODE,
|
||||
"wp_color_representation_surface_v1@%"PRIu32" "
|
||||
"Invalid alpha mode (%u)",
|
||||
wl_resource_get_id(resource), alpha_mode);
|
||||
return;
|
||||
}
|
||||
|
||||
surface->pending.color_representation.alpha_mode = alpha_mode;
|
||||
}
|
||||
|
||||
static void
|
||||
cr_set_coefficients_and_range(struct wl_client *client,
|
||||
struct wl_resource *resource,
|
||||
uint32_t coefficients,
|
||||
uint32_t range)
|
||||
{
|
||||
struct weston_surface *surface =
|
||||
wl_resource_get_user_data(resource);
|
||||
struct weston_color_representation *color_representation;
|
||||
bool supported = false;
|
||||
|
||||
if (!surface) {
|
||||
wl_resource_post_error(resource,
|
||||
WP_COLOR_REPRESENTATION_SURFACE_V1_ERROR_INERT,
|
||||
"wp_color_representation_surface_v1@%"PRIu32" "
|
||||
"The object is inert.",
|
||||
wl_resource_get_id(resource));
|
||||
return;
|
||||
}
|
||||
|
||||
weston_assert_ptr_eq(surface->compositor,
|
||||
surface->color_representation_resource, resource);
|
||||
|
||||
color_representation = &surface->pending.color_representation;
|
||||
|
||||
for (unsigned int i = 0; i < ARRAY_LENGTH(supported_coeffs_and_ranges); i++) {
|
||||
if (supported_coeffs_and_ranges[i].coefficients == coefficients &&
|
||||
supported_coeffs_and_ranges[i].range == range) {
|
||||
supported = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!supported) {
|
||||
wl_resource_post_error(resource,
|
||||
WP_COLOR_REPRESENTATION_SURFACE_V1_ERROR_COEFFICIENTS,
|
||||
"wp_color_representation_surface_v1@%"PRIu32" "
|
||||
"Invalid coefficients (%u) or range (%u).",
|
||||
wl_resource_get_id(resource), coefficients, range);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (coefficients) {
|
||||
case WP_COLOR_REPRESENTATION_SURFACE_V1_COEFFICIENTS_IDENTITY:
|
||||
color_representation->matrix_coefficients = WESTON_COLOR_MATRIX_COEF_IDENTITY;
|
||||
break;
|
||||
case WP_COLOR_REPRESENTATION_SURFACE_V1_COEFFICIENTS_BT709:
|
||||
color_representation->matrix_coefficients = WESTON_COLOR_MATRIX_COEF_BT709;
|
||||
break;
|
||||
case WP_COLOR_REPRESENTATION_SURFACE_V1_COEFFICIENTS_BT601:
|
||||
color_representation->matrix_coefficients = WESTON_COLOR_MATRIX_COEF_BT601;
|
||||
break;
|
||||
case WP_COLOR_REPRESENTATION_SURFACE_V1_COEFFICIENTS_BT2020:
|
||||
color_representation->matrix_coefficients = WESTON_COLOR_MATRIX_COEF_BT2020;
|
||||
break;
|
||||
default:
|
||||
weston_assert_not_reached(surface->compositor, "unsupported coefficients");
|
||||
}
|
||||
|
||||
switch (range) {
|
||||
case WP_COLOR_REPRESENTATION_SURFACE_V1_RANGE_FULL:
|
||||
color_representation->quant_range = WESTON_COLOR_QUANT_RANGE_FULL;
|
||||
break;
|
||||
case WP_COLOR_REPRESENTATION_SURFACE_V1_RANGE_LIMITED:
|
||||
color_representation->quant_range = WESTON_COLOR_QUANT_RANGE_LIMITED;
|
||||
break;
|
||||
default:
|
||||
weston_assert_not_reached(surface->compositor, "unsupported range");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
cr_set_chroma_location(struct wl_client *client,
|
||||
struct wl_resource *resource,
|
||||
uint32_t chroma_location)
|
||||
{
|
||||
struct weston_surface *surface =
|
||||
wl_resource_get_user_data(resource);
|
||||
struct weston_color_representation *color_representation;
|
||||
|
||||
if (!surface) {
|
||||
wl_resource_post_error(resource,
|
||||
WP_COLOR_REPRESENTATION_SURFACE_V1_ERROR_INERT,
|
||||
"wp_color_representation_surface_v1@%"PRIu32" "
|
||||
"The object is inert.",
|
||||
wl_resource_get_id(resource));
|
||||
return;
|
||||
}
|
||||
|
||||
weston_assert_ptr_eq(surface->compositor,
|
||||
surface->color_representation_resource, resource);
|
||||
|
||||
color_representation = &surface->pending.color_representation;
|
||||
|
||||
switch (chroma_location) {
|
||||
case WP_COLOR_REPRESENTATION_SURFACE_V1_CHROMA_LOCATION_TYPE_0:
|
||||
color_representation->chroma_location = WESTON_YCBCR_CHROMA_LOCATION_TYPE_0;
|
||||
break;
|
||||
case WP_COLOR_REPRESENTATION_SURFACE_V1_CHROMA_LOCATION_TYPE_1:
|
||||
color_representation->chroma_location = WESTON_YCBCR_CHROMA_LOCATION_TYPE_1;
|
||||
break;
|
||||
case WP_COLOR_REPRESENTATION_SURFACE_V1_CHROMA_LOCATION_TYPE_2:
|
||||
color_representation->chroma_location = WESTON_YCBCR_CHROMA_LOCATION_TYPE_2;
|
||||
break;
|
||||
case WP_COLOR_REPRESENTATION_SURFACE_V1_CHROMA_LOCATION_TYPE_3:
|
||||
color_representation->chroma_location = WESTON_YCBCR_CHROMA_LOCATION_TYPE_3;
|
||||
break;
|
||||
case WP_COLOR_REPRESENTATION_SURFACE_V1_CHROMA_LOCATION_TYPE_4:
|
||||
color_representation->chroma_location = WESTON_YCBCR_CHROMA_LOCATION_TYPE_4;
|
||||
break;
|
||||
case WP_COLOR_REPRESENTATION_SURFACE_V1_CHROMA_LOCATION_TYPE_5:
|
||||
color_representation->chroma_location = WESTON_YCBCR_CHROMA_LOCATION_TYPE_5;
|
||||
break;
|
||||
default:
|
||||
wl_resource_post_error(resource,
|
||||
WP_COLOR_REPRESENTATION_SURFACE_V1_ERROR_CHROMA_LOCATION,
|
||||
"wp_color_representation_surface_v1@%"PRIu32" "
|
||||
"Invalid chroma location (%u).",
|
||||
wl_resource_get_id(resource),
|
||||
chroma_location);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct wp_color_representation_surface_v1_interface cr_implementation = {
|
||||
.destroy = cr_destroy,
|
||||
.set_alpha_mode = cr_set_alpha_mode,
|
||||
.set_coefficients_and_range = cr_set_coefficients_and_range,
|
||||
.set_chroma_location = cr_set_chroma_location,
|
||||
};
|
||||
|
||||
static void
|
||||
cr_manager_destroy(struct wl_client *client,
|
||||
struct wl_resource *resource)
|
||||
{
|
||||
wl_resource_destroy(resource);
|
||||
}
|
||||
|
||||
static void
|
||||
cr_manager_get_surface(struct wl_client *client,
|
||||
struct wl_resource *resource,
|
||||
uint32_t id,
|
||||
struct wl_resource *surface_resource)
|
||||
{
|
||||
struct weston_surface *surface =
|
||||
wl_resource_get_user_data(surface_resource);
|
||||
struct wl_resource *color_representation_resource;
|
||||
|
||||
if (surface->color_representation_resource) {
|
||||
wl_resource_post_error(resource,
|
||||
WP_COLOR_REPRESENTATION_MANAGER_V1_ERROR_SURFACE_EXISTS,
|
||||
"a color representation surface for that surface already exists");
|
||||
return;
|
||||
}
|
||||
|
||||
color_representation_resource = wl_resource_create(client,
|
||||
&wp_color_representation_surface_v1_interface,
|
||||
wl_resource_get_version(resource), id);
|
||||
if (color_representation_resource == NULL) {
|
||||
wl_client_post_no_memory(client);
|
||||
return;
|
||||
}
|
||||
|
||||
wl_resource_set_implementation(color_representation_resource,
|
||||
&cr_implementation, surface, destroy_color_representation);
|
||||
|
||||
surface->color_representation_resource = color_representation_resource;
|
||||
}
|
||||
|
||||
static const struct wp_color_representation_manager_v1_interface
|
||||
cr_manager_implementation = {
|
||||
.destroy = cr_manager_destroy,
|
||||
.get_surface = cr_manager_get_surface,
|
||||
};
|
||||
|
||||
static void
|
||||
bind_color_representation(struct wl_client *client, void *data, uint32_t version,
|
||||
uint32_t id)
|
||||
{
|
||||
struct wl_resource *resource;
|
||||
struct weston_compositor *compositor = data;
|
||||
|
||||
resource = wl_resource_create(client,
|
||||
&wp_color_representation_manager_v1_interface, version, id);
|
||||
if (!resource) {
|
||||
wl_client_post_no_memory(client);
|
||||
return;
|
||||
}
|
||||
|
||||
wl_resource_set_implementation(resource, &cr_manager_implementation,
|
||||
compositor, NULL);
|
||||
|
||||
for (unsigned int i = 0; i < ARRAY_LENGTH(supported_alpha_modes); i++) {
|
||||
wp_color_representation_manager_v1_send_supported_alpha_mode(
|
||||
resource,
|
||||
supported_alpha_modes[i]);
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < ARRAY_LENGTH(supported_coeffs_and_ranges); i++) {
|
||||
wp_color_representation_manager_v1_send_supported_coefficients_and_ranges(
|
||||
resource,
|
||||
supported_coeffs_and_ranges[i].coefficients,
|
||||
supported_coeffs_and_ranges[i].range);
|
||||
}
|
||||
|
||||
wp_color_representation_manager_v1_send_done(resource);
|
||||
}
|
||||
|
||||
/** Advertise color-representation support
|
||||
*
|
||||
* Calling this initializes the color-representation protocol support, so that
|
||||
* wp_color_representation_manager_v1_interface will be advertised to clients.
|
||||
* Essentially it creates a global. Do not call this function multiple times in
|
||||
* the compositor's lifetime. There is no way to deinit explicitly, globals will
|
||||
* be reaped when the wl_display gets destroyed.
|
||||
*
|
||||
* \param compositor The compositor to init for.
|
||||
* \return Zero on success, -1 on failure.
|
||||
*/
|
||||
int
|
||||
weston_compositor_enable_color_representation_protocol(struct weston_compositor *compositor)
|
||||
{
|
||||
uint32_t version = 1;
|
||||
|
||||
if (!(compositor->capabilities & WESTON_CAP_COLOR_REP)) {
|
||||
weston_log("Color representation not supported by renderer\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!wl_global_create(compositor->wl_display,
|
||||
&wp_color_representation_manager_v1_interface,
|
||||
version, compositor, bind_color_representation))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct weston_color_matrix_coef_info color_matrix_coef_info_map[] = {
|
||||
{ WESTON_COLOR_MATRIX_COEF_UNSET, "unset", WDRM_PLANE_COLOR_ENCODING__COUNT },
|
||||
{ WESTON_COLOR_MATRIX_COEF_IDENTITY, "default", WDRM_PLANE_COLOR_ENCODING__COUNT },
|
||||
{ WESTON_COLOR_MATRIX_COEF_BT601, "BT.601", WDRM_PLANE_COLOR_ENCODING_BT601 },
|
||||
{ WESTON_COLOR_MATRIX_COEF_BT709, "BT.709", WDRM_PLANE_COLOR_ENCODING_BT709 },
|
||||
{ WESTON_COLOR_MATRIX_COEF_BT2020, "BT.2020", WDRM_PLANE_COLOR_ENCODING_BT2020 },
|
||||
};
|
||||
|
||||
WL_EXPORT const struct weston_color_matrix_coef_info *
|
||||
weston_color_matrix_coef_info_get(enum weston_color_matrix_coef coefficients)
|
||||
{
|
||||
for (unsigned i = 0; i < ARRAY_LENGTH(color_matrix_coef_info_map); i++)
|
||||
if (color_matrix_coef_info_map[i].coefficients == coefficients)
|
||||
return &color_matrix_coef_info_map[i];
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const struct weston_color_quant_range_info color_quant_range_info_map[] = {
|
||||
{ WESTON_COLOR_QUANT_RANGE_UNSET, "unset", WDRM_PLANE_COLOR_RANGE__COUNT },
|
||||
{ WESTON_COLOR_QUANT_RANGE_FULL, "full", WDRM_PLANE_COLOR_RANGE_FULL },
|
||||
{ WESTON_COLOR_QUANT_RANGE_LIMITED, "limited", WDRM_PLANE_COLOR_RANGE_LIMITED },
|
||||
};
|
||||
|
||||
WL_EXPORT const struct weston_color_quant_range_info *
|
||||
weston_color_quant_range_info_get(enum weston_color_quant_range range)
|
||||
{
|
||||
for (unsigned i = 0; i < ARRAY_LENGTH(color_quant_range_info_map); i++)
|
||||
if (color_quant_range_info_map[i].range == range)
|
||||
return &color_quant_range_info_map[i];
|
||||
|
||||
return NULL;
|
||||
}
|
||||
78
libweston/color-representation.h
Normal file
78
libweston/color-representation.h
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* Copyright 2025 Collabora, Ltd.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the
|
||||
* next paragraph) shall be included in all copies or substantial
|
||||
* portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <libweston/libweston.h>
|
||||
|
||||
#include "backend-drm/drm-kms-enums.h"
|
||||
|
||||
void
|
||||
weston_reset_color_representation(struct weston_color_representation *color_rep);
|
||||
|
||||
struct weston_color_representation
|
||||
weston_fill_color_representation(const struct weston_color_representation *color_rep_in,
|
||||
const struct pixel_format_info *info);
|
||||
|
||||
enum weston_cr_comparison_flag {
|
||||
WESTON_CR_COMPARISON_FLAG_NONE = 0,
|
||||
WESTON_CR_COMPARISON_FLAG_IGNORE_ALPHA = 1,
|
||||
WESTON_CR_COMPARISON_FLAG_IGNORE_CHROMA_LOCATION = 2,
|
||||
};
|
||||
|
||||
bool
|
||||
weston_color_representation_equal(struct weston_color_representation *color_rep_A,
|
||||
struct weston_color_representation *color_rep_B,
|
||||
enum weston_cr_comparison_flag flags);
|
||||
|
||||
void
|
||||
weston_get_color_representation_matrix(struct weston_compositor *compositor,
|
||||
enum weston_color_matrix_coef coefficients,
|
||||
enum weston_color_quant_range range,
|
||||
struct weston_color_representation_matrix *cr_matrix);
|
||||
|
||||
bool
|
||||
weston_surface_check_pending_color_representation_valid(const struct weston_surface *surface);
|
||||
|
||||
int
|
||||
weston_compositor_enable_color_representation_protocol(struct weston_compositor *compositor);
|
||||
|
||||
struct weston_color_quant_range_info {
|
||||
enum weston_color_quant_range range;
|
||||
const char *name;
|
||||
enum wdrm_plane_color_range wdrm;
|
||||
};
|
||||
|
||||
const struct weston_color_quant_range_info *
|
||||
weston_color_quant_range_info_get(enum weston_color_quant_range range);
|
||||
|
||||
struct weston_color_matrix_coef_info {
|
||||
enum weston_color_matrix_coef coefficients;
|
||||
const char *name;
|
||||
enum wdrm_plane_color_encoding wdrm;
|
||||
};
|
||||
|
||||
const struct weston_color_matrix_coef_info *
|
||||
weston_color_matrix_coef_info_get(enum weston_color_matrix_coef coefficients);
|
||||
|
|
@ -84,6 +84,7 @@
|
|||
#include "libweston-internal.h"
|
||||
#include "color.h"
|
||||
#include "color-management.h"
|
||||
#include "color-representation.h"
|
||||
#include "id-number-allocator.h"
|
||||
#include "output-capture.h"
|
||||
#include "pixman-renderer.h"
|
||||
|
|
@ -1014,6 +1015,8 @@ weston_surface_create(struct weston_compositor *compositor)
|
|||
/* Also part of the CM&HDR protocol extension implementation. */
|
||||
weston_surface_update_preferred_color_profile(surface);
|
||||
|
||||
weston_reset_color_representation(&surface->color_representation);
|
||||
|
||||
wl_list_init(&surface->fifo_barrier_link);
|
||||
|
||||
return surface;
|
||||
|
|
@ -2757,6 +2760,11 @@ destroy_surface(struct wl_resource *resource)
|
|||
NULL);
|
||||
}
|
||||
|
||||
if (surface->color_representation_resource) {
|
||||
wl_resource_set_user_data(surface->color_representation_resource,
|
||||
NULL);
|
||||
}
|
||||
|
||||
weston_surface_unref(surface);
|
||||
}
|
||||
|
||||
|
|
@ -5063,6 +5071,9 @@ surface_commit(struct wl_client *client, struct wl_resource *resource)
|
|||
return;
|
||||
}
|
||||
|
||||
if (!weston_surface_check_pending_color_representation_valid(surface))
|
||||
return;
|
||||
|
||||
weston_surface_commit(surface);
|
||||
}
|
||||
|
||||
|
|
@ -10136,6 +10147,9 @@ weston_compositor_backends_loaded(struct weston_compositor *compositor)
|
|||
return -1;
|
||||
}
|
||||
|
||||
if (weston_compositor_enable_color_representation_protocol(compositor) < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ srcs_libweston = [
|
|||
'color.c',
|
||||
'color-properties.c',
|
||||
'color-management.c',
|
||||
'color-representation.c',
|
||||
'color-noop.c',
|
||||
'color-operations.c',
|
||||
'color-profile-param-builder.c',
|
||||
|
|
@ -49,6 +50,8 @@ srcs_libweston = [
|
|||
'weston-direct-display.c',
|
||||
color_management_v1_protocol_c,
|
||||
color_management_v1_server_protocol_h,
|
||||
color_representation_v1_protocol_c,
|
||||
color_representation_v1_server_protocol_h,
|
||||
commit_timing_v1_protocol_c,
|
||||
commit_timing_v1_server_protocol_h,
|
||||
fifo_v1_protocol_c,
|
||||
|
|
|
|||
|
|
@ -95,29 +95,16 @@ compile_const bool c_need_color_pipeline =
|
|||
compile_const bool c_need_straight_alpha =
|
||||
c_need_color_pipeline || c_color_effect != SHADER_COLOR_EFFECT_NONE;
|
||||
|
||||
uniform HIGHPRECISION mat3 yuv_coefficients;
|
||||
uniform HIGHPRECISION vec3 yuv_offsets;
|
||||
|
||||
vec4
|
||||
yuva2rgba(vec4 yuva)
|
||||
{
|
||||
vec4 color_out;
|
||||
float Y, su, sv;
|
||||
|
||||
/* ITU-R BT.601 & BT.709 quantization (limited range) */
|
||||
|
||||
Y = 255.0/219.0 * (yuva.x - 16.0/255.0);
|
||||
|
||||
/* Remove offset 128/255, but the 255/224 multiplier comes later */
|
||||
su = yuva.y - 128.0/255.0;
|
||||
sv = yuva.z - 128.0/255.0;
|
||||
|
||||
/*
|
||||
* ITU-R BT.709 encoding coefficients (inverse), with the
|
||||
* 255/224 limited range multiplier already included in the
|
||||
* factors for su (Cb) and sv (Cr).
|
||||
*/
|
||||
color_out.r = Y + 1.79274107 * sv;
|
||||
color_out.g = Y - 0.21324861 * su - 0.53290933 * sv;
|
||||
color_out.b = Y + 2.11240179 * su;
|
||||
|
||||
color_out.rgb = yuv_coefficients * (yuva.xyz - yuv_offsets);
|
||||
color_out.rgb *= yuva.w;
|
||||
color_out.a = yuva.w;
|
||||
|
||||
return color_out;
|
||||
|
|
|
|||
|
|
@ -390,6 +390,9 @@ struct gl_shader_config {
|
|||
union gl_shader_config_color_curve color_pre_curve;
|
||||
union gl_shader_config_color_mapping color_mapping;
|
||||
union gl_shader_config_color_curve color_post_curve;
|
||||
|
||||
enum weston_color_matrix_coef yuv_coefficients;
|
||||
enum weston_color_quant_range yuv_range;
|
||||
};
|
||||
|
||||
struct gl_renderer {
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@
|
|||
#include "timeline.h"
|
||||
|
||||
#include "color.h"
|
||||
#include "color-representation.h"
|
||||
#include "gl-renderer.h"
|
||||
#include "gl-renderer-internal.h"
|
||||
#include "vertex-clipping.h"
|
||||
|
|
@ -63,6 +64,7 @@
|
|||
#include "shared/platform.h"
|
||||
#include "shared/string-helpers.h"
|
||||
#include "shared/timespec-util.h"
|
||||
#include "shared/weston-assert.h"
|
||||
#include "shared/weston-drm-fourcc.h"
|
||||
#include "shared/weston-egl-ext.h"
|
||||
#include "shared/xalloc.h"
|
||||
|
|
@ -251,6 +253,11 @@ struct yuv_format_descriptor {
|
|||
struct yuv_plane_descriptor plane[3];
|
||||
};
|
||||
|
||||
struct gl_color_egl_image {
|
||||
EGLImageKHR image;
|
||||
struct weston_color_representation import_color_rep;
|
||||
};
|
||||
|
||||
struct gl_buffer_state {
|
||||
struct gl_renderer *gr;
|
||||
|
||||
|
|
@ -265,13 +272,24 @@ struct gl_buffer_state {
|
|||
int num_images;
|
||||
enum gl_shader_texture_variant shader_variant;
|
||||
|
||||
struct weston_color_representation egl_image_import_color_rep;
|
||||
|
||||
/* For non-default color representations we need to re-import
|
||||
* EGLImageKHR with different attributes for
|
||||
* EGL_YUV_COLOR_SPACE_HINT_EXT, EGL_SAMPLE_RANGE_HINT_EXT and, in the
|
||||
* future, EGL_YUV_CHROMA_HORIZONTAL_SITING_HINT_EXT and
|
||||
* EGL_YUV_CHROMA_VERTICAL_SITING_HINT_EXT */
|
||||
struct wl_array reimported_egl_images;
|
||||
struct gl_color_egl_image *active_reimported_egl_image;
|
||||
|
||||
/* These values can refer to the EGLImageKHR's in either images[3] or
|
||||
* active_reimported_egl_image->image. Textures will get destroyed and
|
||||
* recreated when switching. */
|
||||
struct gl_format_info texture_format[3];
|
||||
struct gl_texture_parameters parameters[3];
|
||||
GLuint textures[3];
|
||||
int num_textures;
|
||||
|
||||
bool specified;
|
||||
|
||||
struct wl_listener destroy_listener;
|
||||
};
|
||||
|
||||
|
|
@ -888,7 +906,9 @@ gl_renderer_create_renderbuffer(struct weston_output *output,
|
|||
}
|
||||
|
||||
static EGLImageKHR
|
||||
import_simple_dmabuf(struct gl_renderer *, const struct dmabuf_attributes *);
|
||||
import_simple_dmabuf(struct gl_renderer *,
|
||||
const struct dmabuf_attributes *,
|
||||
const struct weston_color_representation *);
|
||||
|
||||
static weston_renderbuffer_t
|
||||
gl_renderer_create_renderbuffer_dmabuf(struct weston_output *output,
|
||||
|
|
@ -899,10 +919,14 @@ gl_renderer_create_renderbuffer_dmabuf(struct weston_output *output,
|
|||
struct gl_renderer *gr = get_renderer(output->compositor);
|
||||
struct dmabuf_attributes *attributes = dmabuf->attributes;
|
||||
struct gl_renderbuffer *renderbuffer;
|
||||
const struct pixel_format_info *info;
|
||||
EGLImageKHR image;
|
||||
GLuint fb, rb;
|
||||
|
||||
image = import_simple_dmabuf(gr, attributes);
|
||||
info = pixel_format_get_info(attributes->format);
|
||||
assert(info->color_model != COLOR_MODEL_YUV);
|
||||
|
||||
image = import_simple_dmabuf(gr, attributes, NULL);
|
||||
if (image == EGL_NO_IMAGE_KHR) {
|
||||
weston_log("Failed to import dmabuf\n");
|
||||
return NULL;
|
||||
|
|
@ -1442,6 +1466,142 @@ prepare_solid_draw(struct gl_shader_config *sconf,
|
|||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
recreate_and_specify_textures(struct gl_buffer_state *gb,
|
||||
EGLImageKHR *images)
|
||||
{
|
||||
struct gl_renderer *gr = gb->gr;
|
||||
GLenum target;
|
||||
|
||||
if (gb->num_textures > 0)
|
||||
glDeleteTextures(gb->num_textures, gb->textures);
|
||||
|
||||
glGenTextures(gb->num_images, gb->textures);
|
||||
gb->num_textures = gb->num_images;
|
||||
|
||||
target = gl_shader_texture_variant_get_target(gb->shader_variant);
|
||||
|
||||
for (int i = 0; i < gb->num_images; i++) {
|
||||
gl_texture_parameters_init(gb->gr, &gb->parameters[i], target,
|
||||
NULL, NULL, gb->texture_format[i].swizzles.array, false);
|
||||
}
|
||||
|
||||
for (int i = 0; i < gb->num_images; ++i) {
|
||||
glBindTexture(gb->parameters[i].target, gb->textures[i]);
|
||||
if (gl_extensions_has(gr, EXTENSION_EXT_EGL_IMAGE_STORAGE)) {
|
||||
gr->image_target_tex_storage(gb->parameters[i].target,
|
||||
images[i], NULL);
|
||||
} else {
|
||||
gr->image_target_texture_2d(gb->parameters[i].target,
|
||||
images[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static struct gl_color_egl_image *
|
||||
ensure_color_egl_image(struct gl_surface_state *gs,
|
||||
struct weston_color_representation *color_rep)
|
||||
{
|
||||
struct weston_buffer *buffer = gs->buffer_ref.buffer;
|
||||
struct gl_buffer_state *gb = gs->buffer;
|
||||
struct gl_color_egl_image *color_egl_image = NULL;
|
||||
struct gl_color_egl_image *color_egl_image_cand;
|
||||
|
||||
wl_array_for_each(color_egl_image_cand, &gb->reimported_egl_images) {
|
||||
if (!weston_color_representation_equal(&color_egl_image_cand->import_color_rep,
|
||||
color_rep,
|
||||
WESTON_CR_COMPARISON_FLAG_IGNORE_ALPHA |
|
||||
WESTON_CR_COMPARISON_FLAG_IGNORE_CHROMA_LOCATION))
|
||||
continue;
|
||||
|
||||
color_egl_image = color_egl_image_cand;
|
||||
break;
|
||||
}
|
||||
if (!color_egl_image) {
|
||||
struct linux_dmabuf_buffer *dmabuf;
|
||||
EGLImageKHR image;
|
||||
|
||||
assert(buffer->dmabuf);
|
||||
dmabuf = buffer->dmabuf;
|
||||
|
||||
image = import_simple_dmabuf(gb->gr,
|
||||
&dmabuf->attributes,
|
||||
color_rep);
|
||||
if (image == EGL_NO_IMAGE_KHR)
|
||||
return NULL;
|
||||
|
||||
color_egl_image = wl_array_add(&gb->reimported_egl_images,
|
||||
sizeof *color_egl_image);
|
||||
assert(color_egl_image);
|
||||
color_egl_image->image = image;
|
||||
color_egl_image->import_color_rep = *color_rep;
|
||||
}
|
||||
return color_egl_image;
|
||||
}
|
||||
|
||||
static void
|
||||
ensure_images_and_textures(struct gl_surface_state *gs)
|
||||
{
|
||||
struct weston_surface *surface = gs->surface;
|
||||
struct weston_compositor *compositor = surface->compositor;
|
||||
struct weston_buffer *buffer = gs->buffer_ref.buffer;
|
||||
const struct pixel_format_info *info = buffer->pixel_format;
|
||||
struct gl_buffer_state *gb = gs->buffer;
|
||||
struct weston_color_representation color_rep;
|
||||
|
||||
if (buffer->type != WESTON_BUFFER_DMABUF ||
|
||||
(gb->shader_variant != SHADER_VARIANT_RGBA &&
|
||||
gb->shader_variant != SHADER_VARIANT_EXTERNAL)) {
|
||||
if (gb->num_textures == 0)
|
||||
recreate_and_specify_textures(gb, gb->images);
|
||||
return;
|
||||
}
|
||||
|
||||
color_rep =
|
||||
weston_fill_color_representation(&surface->color_representation,
|
||||
info);
|
||||
|
||||
/* Check if we need to re-import the EGLImage with non-default YCbCr
|
||||
* attributes. */
|
||||
if (!weston_color_representation_equal(&gb->egl_image_import_color_rep,
|
||||
&color_rep,
|
||||
WESTON_CR_COMPARISON_FLAG_IGNORE_ALPHA |
|
||||
WESTON_CR_COMPARISON_FLAG_IGNORE_CHROMA_LOCATION)) {
|
||||
struct gl_color_egl_image *color_egl_image = NULL;
|
||||
|
||||
|
||||
color_egl_image = ensure_color_egl_image(gs, &color_rep);
|
||||
if (!color_egl_image) {
|
||||
weston_log("GL-renderer: failed to re-import EGLImageKHR\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (gb->active_reimported_egl_image == color_egl_image) {
|
||||
weston_assert_int_gt(compositor, gb->num_textures, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
weston_assert_int_eq(compositor, gb->num_images, 1);
|
||||
recreate_and_specify_textures(gb, &color_egl_image->image);
|
||||
gb->active_reimported_egl_image = color_egl_image;
|
||||
return;
|
||||
}
|
||||
|
||||
/* We switched from an EGLImage with non-default YCbCr attributes to
|
||||
* default values. Recreate and bind textures. */
|
||||
if (gb->active_reimported_egl_image != NULL) {
|
||||
weston_assert_int_eq(compositor, gb->num_images, 1);
|
||||
recreate_and_specify_textures(gb, gb->images);
|
||||
gb->active_reimported_egl_image = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
out:
|
||||
/* Ensure we create and bind textures. */
|
||||
if (gb->num_textures == 0)
|
||||
recreate_and_specify_textures(gb, gb->images);
|
||||
}
|
||||
|
||||
static void
|
||||
gl_shader_config_set_input_textures(struct gl_shader_config *sconf,
|
||||
struct gl_buffer_state *gb)
|
||||
|
|
@ -1464,9 +1624,12 @@ prepare_textured_draw(struct gl_shader_config *sconf,
|
|||
struct gl_buffer_state *gb = gs->buffer;
|
||||
struct gl_output_state *go = get_output_state(pnode->output);
|
||||
struct weston_buffer *buffer = gs->buffer_ref.buffer;
|
||||
struct weston_color_representation color_rep;
|
||||
GLint filter;
|
||||
int i;
|
||||
|
||||
ensure_images_and_textures(gs);
|
||||
|
||||
*sconf = (struct gl_shader_config) {
|
||||
.req.texcoord_input = SHADER_TEXCOORD_INPUT_SURFACE,
|
||||
.projection = pnode->view->transform.matrix,
|
||||
|
|
@ -1508,6 +1671,12 @@ prepare_textured_draw(struct gl_shader_config *sconf,
|
|||
return false;
|
||||
}
|
||||
|
||||
color_rep =
|
||||
weston_fill_color_representation(&pnode->surface->color_representation,
|
||||
buffer->pixel_format);
|
||||
sconf->yuv_coefficients = color_rep.matrix_coefficients;
|
||||
sconf->yuv_range = color_rep.quant_range;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -2873,6 +3042,7 @@ done:
|
|||
static void
|
||||
destroy_buffer_state(struct gl_buffer_state *gb)
|
||||
{
|
||||
struct gl_color_egl_image *color_egl_image;
|
||||
int i;
|
||||
|
||||
glDeleteTextures(gb->num_textures, gb->textures);
|
||||
|
|
@ -2880,6 +3050,10 @@ destroy_buffer_state(struct gl_buffer_state *gb)
|
|||
for (i = 0; i < gb->num_images; i++)
|
||||
gb->gr->destroy_image(gb->gr->egl_display, gb->images[i]);
|
||||
|
||||
wl_array_for_each(color_egl_image, &gb->reimported_egl_images)
|
||||
gb->gr->destroy_image(gb->gr->egl_display, color_egl_image->image);
|
||||
wl_array_release(&gb->reimported_egl_images);
|
||||
|
||||
pixman_region32_fini(&gb->texture_damage);
|
||||
wl_list_remove(&gb->destroy_listener.link);
|
||||
|
||||
|
|
@ -2899,23 +3073,6 @@ handle_buffer_destroy(struct wl_listener *listener, void *data)
|
|||
destroy_buffer_state(gb);
|
||||
}
|
||||
|
||||
static void
|
||||
ensure_textures(struct gl_buffer_state *gb, GLenum target, int num_textures)
|
||||
{
|
||||
int i;
|
||||
|
||||
assert(gb->num_textures == 0);
|
||||
|
||||
glGenTextures(num_textures, gb->textures);
|
||||
gb->num_textures = num_textures;
|
||||
|
||||
for (i = 0; i < num_textures; i++)
|
||||
gl_texture_parameters_init(gb->gr, &gb->parameters[i], target,
|
||||
NULL, NULL,
|
||||
gb->texture_format[i].swizzles.array,
|
||||
false);
|
||||
}
|
||||
|
||||
static void
|
||||
gl_renderer_attach_shm(struct weston_surface *es, struct weston_buffer *buffer)
|
||||
{
|
||||
|
|
@ -3077,7 +3234,6 @@ gl_renderer_fill_buffer_info(struct weston_compositor *ec,
|
|||
struct gl_buffer_state *gb;
|
||||
EGLint format;
|
||||
uint32_t fourcc;
|
||||
GLenum target;
|
||||
EGLint y_inverted;
|
||||
bool rgb, ret = true;
|
||||
int i;
|
||||
|
|
@ -3195,9 +3351,6 @@ gl_renderer_fill_buffer_info(struct weston_compositor *ec,
|
|||
}
|
||||
}
|
||||
|
||||
target = gl_shader_texture_variant_get_target(gb->shader_variant);
|
||||
ensure_textures(gb, target, gb->num_images);
|
||||
|
||||
buffer->renderer_private = gb;
|
||||
gb->destroy_listener.notify = handle_buffer_destroy;
|
||||
wl_signal_add(&buffer->destroy_signal, &gb->destroy_listener);
|
||||
|
|
@ -3223,8 +3376,10 @@ gl_renderer_destroy_dmabuf(struct linux_dmabuf_buffer *dmabuf)
|
|||
|
||||
static EGLImageKHR
|
||||
import_simple_dmabuf(struct gl_renderer *gr,
|
||||
const struct dmabuf_attributes *attributes)
|
||||
const struct dmabuf_attributes *attributes,
|
||||
const struct weston_color_representation *color_rep)
|
||||
{
|
||||
const struct pixel_format_info *info;
|
||||
EGLint attribs[53];
|
||||
int atti = 0;
|
||||
bool has_modifier;
|
||||
|
|
@ -3314,11 +3469,41 @@ import_simple_dmabuf(struct gl_renderer *gr,
|
|||
}
|
||||
}
|
||||
|
||||
attribs[atti++] = EGL_YUV_COLOR_SPACE_HINT_EXT;
|
||||
attribs[atti++] = EGL_ITU_REC709_EXT;
|
||||
info = pixel_format_get_info(attributes->format);
|
||||
assert(info);
|
||||
if (info->color_model == COLOR_MODEL_YUV) {
|
||||
assert(color_rep);
|
||||
|
||||
attribs[atti++] = EGL_SAMPLE_RANGE_HINT_EXT;
|
||||
attribs[atti++] = EGL_YUV_NARROW_RANGE_EXT;
|
||||
attribs[atti++] = EGL_YUV_COLOR_SPACE_HINT_EXT;
|
||||
switch (color_rep->matrix_coefficients) {
|
||||
case WESTON_COLOR_MATRIX_COEF_BT601:
|
||||
attribs[atti++] = EGL_ITU_REC601_EXT;
|
||||
break;
|
||||
case WESTON_COLOR_MATRIX_COEF_BT709:
|
||||
attribs[atti++] = EGL_ITU_REC709_EXT;
|
||||
break;
|
||||
case WESTON_COLOR_MATRIX_COEF_BT2020:
|
||||
attribs[atti++] = EGL_ITU_REC2020_EXT;
|
||||
break;
|
||||
case WESTON_COLOR_MATRIX_COEF_UNSET:
|
||||
case WESTON_COLOR_MATRIX_COEF_IDENTITY:
|
||||
weston_assert_not_reached(gr->compositor,
|
||||
"invalid matrix coefficients");
|
||||
}
|
||||
|
||||
attribs[atti++] = EGL_SAMPLE_RANGE_HINT_EXT;
|
||||
switch (color_rep->quant_range) {
|
||||
case WESTON_COLOR_QUANT_RANGE_LIMITED:
|
||||
attribs[atti++] = EGL_YUV_NARROW_RANGE_EXT;
|
||||
break;
|
||||
case WESTON_COLOR_QUANT_RANGE_FULL:
|
||||
attribs[atti++] = EGL_YUV_FULL_RANGE_EXT;
|
||||
break;
|
||||
case WESTON_COLOR_QUANT_RANGE_UNSET:
|
||||
weston_assert_not_reached(gr->compositor,
|
||||
"invalid quantization range");
|
||||
}
|
||||
}
|
||||
|
||||
attribs[atti++] = EGL_NONE;
|
||||
|
||||
|
|
@ -3333,6 +3518,7 @@ import_dmabuf_single_plane(struct gl_renderer *gr,
|
|||
const struct dmabuf_attributes *attributes,
|
||||
const struct yuv_plane_descriptor *descriptor)
|
||||
{
|
||||
const struct pixel_format_info *plane_info;
|
||||
struct dmabuf_attributes plane;
|
||||
EGLImageKHR image;
|
||||
char fmt[4];
|
||||
|
|
@ -3348,7 +3534,10 @@ import_dmabuf_single_plane(struct gl_renderer *gr,
|
|||
plane.stride[0] = attributes->stride[descriptor->plane_index];
|
||||
plane.modifier = attributes->modifier;
|
||||
|
||||
image = import_simple_dmabuf(gr, &plane);
|
||||
plane_info = pixel_format_get_info(plane.format);
|
||||
assert(plane_info->color_model != COLOR_MODEL_YUV);
|
||||
|
||||
image = import_simple_dmabuf(gr, &plane, NULL);
|
||||
if (image == EGL_NO_IMAGE_KHR) {
|
||||
weston_log("Failed to import plane %d as %.4s\n",
|
||||
descriptor->plane_index,
|
||||
|
|
@ -3368,7 +3557,6 @@ import_yuv_dmabuf(struct gl_renderer *gr, struct gl_buffer_state *gb,
|
|||
const struct yuv_format_descriptor *format = NULL;
|
||||
const struct pixel_format_info *info;
|
||||
int plane_count;
|
||||
GLenum target;
|
||||
char fmt[4];
|
||||
|
||||
for (i = 0; i < ARRAY_LENGTH(yuv_formats); ++i) {
|
||||
|
|
@ -3419,9 +3607,6 @@ import_yuv_dmabuf(struct gl_renderer *gr, struct gl_buffer_state *gb,
|
|||
gb->num_images = format->output_planes;
|
||||
gb->shader_variant = format->shader_variant;
|
||||
|
||||
target = gl_shader_texture_variant_get_target(gb->shader_variant);
|
||||
ensure_textures(gb, target, gb->num_images);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -3514,6 +3699,7 @@ import_dmabuf(struct gl_renderer *gr,
|
|||
EGLImageKHR egl_image;
|
||||
struct gl_buffer_state *gb;
|
||||
const struct pixel_format_info *info;
|
||||
struct weston_color_representation color_rep;
|
||||
const struct weston_testsuite_quirks *quirks;
|
||||
|
||||
info = pixel_format_get_info(dmabuf->attributes.format);
|
||||
|
|
@ -3533,13 +3719,18 @@ import_dmabuf(struct gl_renderer *gr,
|
|||
info->color_model == COLOR_MODEL_YUV)
|
||||
goto import_yuv;
|
||||
|
||||
egl_image = import_simple_dmabuf(gr, &dmabuf->attributes);
|
||||
weston_reset_color_representation(&color_rep);
|
||||
color_rep = weston_fill_color_representation(&color_rep, info);
|
||||
|
||||
egl_image = import_simple_dmabuf(gr, &dmabuf->attributes,
|
||||
&color_rep);
|
||||
if (egl_image != EGL_NO_IMAGE_KHR) {
|
||||
const GLint swizzles[] = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA };
|
||||
GLenum target = choose_texture_target(gr, &dmabuf->attributes);
|
||||
|
||||
gb->num_images = 1;
|
||||
gb->images[0] = egl_image;
|
||||
gb->egl_image_import_color_rep = color_rep;
|
||||
|
||||
/* The driver defines its own swizzles internally in the case of
|
||||
* a successful dma-buf import so just set default values. */
|
||||
|
|
@ -3553,8 +3744,6 @@ import_dmabuf(struct gl_renderer *gr,
|
|||
gb->shader_variant = SHADER_VARIANT_EXTERNAL;
|
||||
}
|
||||
|
||||
ensure_textures(gb, target, gb->num_images);
|
||||
|
||||
return gb;
|
||||
}
|
||||
|
||||
|
|
@ -3704,30 +3893,12 @@ static void
|
|||
gl_renderer_attach_buffer(struct weston_surface *surface,
|
||||
struct weston_buffer *buffer)
|
||||
{
|
||||
struct gl_renderer *gr = get_renderer(surface->compositor);
|
||||
struct gl_surface_state *gs = get_surface_state(surface);
|
||||
struct gl_buffer_state *gb;
|
||||
int i;
|
||||
|
||||
assert(buffer->renderer_private);
|
||||
gb = buffer->renderer_private;
|
||||
|
||||
gs->buffer = gb;
|
||||
|
||||
if (gb->specified)
|
||||
return;
|
||||
|
||||
for (i = 0; i < gb->num_images; ++i) {
|
||||
glBindTexture(gb->parameters[i].target, gb->textures[i]);
|
||||
if (gl_extensions_has(gr, EXTENSION_EXT_EGL_IMAGE_STORAGE))
|
||||
gr->image_target_tex_storage(gb->parameters[i].target,
|
||||
gb->images[i], NULL);
|
||||
else
|
||||
gr->image_target_texture_2d(gb->parameters[i].target,
|
||||
gb->images[i]);
|
||||
}
|
||||
|
||||
gb->specified = true;
|
||||
}
|
||||
|
||||
static const struct weston_drm_format_array *
|
||||
|
|
@ -4785,6 +4956,7 @@ gl_renderer_display_create(struct weston_compositor *ec,
|
|||
ec->capabilities |= WESTON_CAP_EXPLICIT_SYNC;
|
||||
if (gl_features_has(gr, FEATURE_COLOR_TRANSFORMS))
|
||||
ec->capabilities |= WESTON_CAP_COLOR_OPS;
|
||||
ec->capabilities |= WESTON_CAP_COLOR_REP;
|
||||
|
||||
return 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <libweston/color-representation.h>
|
||||
#include <libweston/libweston.h>
|
||||
#include <libweston/weston-log.h>
|
||||
|
||||
|
|
@ -99,6 +100,8 @@ struct gl_shader {
|
|||
union gl_shader_color_curve_uniforms color_pre_curve;
|
||||
union gl_shader_color_mapping_uniforms color_mapping;
|
||||
union gl_shader_color_curve_uniforms color_post_curve;
|
||||
GLint yuv_offsets_uniform;
|
||||
GLint yuv_coefficients_uniform;
|
||||
};
|
||||
|
||||
static const char *
|
||||
|
|
@ -503,6 +506,12 @@ gl_shader_create(struct gl_renderer *gr,
|
|||
case SHADER_COLOR_MAPPING_IDENTITY:
|
||||
break;
|
||||
}
|
||||
|
||||
shader->yuv_coefficients_uniform =
|
||||
glGetUniformLocation(shader->program, "yuv_coefficients");
|
||||
shader->yuv_offsets_uniform = glGetUniformLocation(shader->program,
|
||||
"yuv_offsets");
|
||||
|
||||
free(conf);
|
||||
|
||||
wl_list_insert(&gr->shader_list, &shader->link);
|
||||
|
|
@ -752,6 +761,28 @@ gl_shader_load_config_mapping(struct weston_compositor *compositor,
|
|||
weston_assert_not_reached(compositor, "unknown enum gl_shader_color_mapping value");
|
||||
}
|
||||
|
||||
static void
|
||||
gl_shader_load_config_representation(struct weston_compositor *compositor,
|
||||
struct gl_shader *shader,
|
||||
const struct gl_shader_config *sconf)
|
||||
{
|
||||
struct weston_color_representation_matrix cr_matrix;
|
||||
|
||||
if (sconf->yuv_coefficients == WESTON_COLOR_MATRIX_COEF_UNSET ||
|
||||
sconf->yuv_coefficients == WESTON_COLOR_MATRIX_COEF_IDENTITY) {
|
||||
assert(shader->yuv_coefficients_uniform == -1);
|
||||
assert(shader->yuv_offsets_uniform == -1);
|
||||
return;
|
||||
}
|
||||
|
||||
weston_get_color_representation_matrix(compositor,
|
||||
sconf->yuv_coefficients, sconf->yuv_range, &cr_matrix);
|
||||
|
||||
glUniformMatrix3fv(shader->yuv_coefficients_uniform, 1, GL_FALSE,
|
||||
cr_matrix.matrix.colmaj);
|
||||
glUniform3fv(shader->yuv_offsets_uniform, 1, cr_matrix.offset.el);
|
||||
}
|
||||
|
||||
bool
|
||||
gl_shader_texture_variant_can_be_premult(enum gl_shader_texture_variant v)
|
||||
{
|
||||
|
|
@ -859,6 +890,8 @@ gl_shader_load_config(struct gl_renderer *gr,
|
|||
&sconf->color_post_curve, &shader->color_post_curve,
|
||||
TEX_UNIT_COLOR_POST_CURVE);
|
||||
|
||||
gl_shader_load_config_representation(gr->compositor, shader, sconf);
|
||||
|
||||
if (sconf->req.wireframe)
|
||||
glUniform1i(shader->tex_uniform_wireframe, TEX_UNIT_WIREFRAME);
|
||||
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
#include "libweston-internal.h"
|
||||
|
||||
#include "backend.h"
|
||||
#include "color-representation.h"
|
||||
#include "pixel-formats.h"
|
||||
#include "shared/fd-util.h"
|
||||
#include "shared/timespec-util.h"
|
||||
|
|
@ -156,6 +157,8 @@ weston_surface_state_init(struct weston_surface *surface,
|
|||
state->color_profile = NULL;
|
||||
state->render_intent = NULL;
|
||||
|
||||
weston_reset_color_representation(&state->color_representation);
|
||||
|
||||
state->fifo_barrier = false;
|
||||
state->fifo_wait = false;
|
||||
|
||||
|
|
@ -376,6 +379,11 @@ weston_surface_apply_state(struct weston_surface *surface,
|
|||
/* wp_presentation.feedback */
|
||||
weston_presentation_feedback_discard_list(&surface->feedback_list);
|
||||
|
||||
/* wp_color_representation_v1.set_alpha_mode */
|
||||
/* wp_color_representation_v1.set_coefficients_and_range */
|
||||
/* wp_color_representation_v1.set_chroma_location */
|
||||
surface->color_representation = state->color_representation;
|
||||
|
||||
/* wl_surface.attach */
|
||||
if (status & WESTON_SURFACE_DIRTY_BUFFER) {
|
||||
/* zwp_surface_synchronization_v1.set_acquire_fence */
|
||||
|
|
@ -650,6 +658,8 @@ weston_surface_state_merge_from(struct weston_surface_state *dst,
|
|||
dst->buffer_viewport.buffer = src->buffer_viewport.buffer;
|
||||
dst->buffer_viewport.surface = src->buffer_viewport.surface;
|
||||
|
||||
dst->color_representation = src->color_representation;
|
||||
|
||||
weston_buffer_reference(&src->buffer_ref,
|
||||
NULL, BUFFER_WILL_NOT_BE_ACCESSED);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
dep_scanner = dependency('wayland-scanner', native: true)
|
||||
prog_scanner = find_program(dep_scanner.get_variable(pkgconfig: 'wayland_scanner'))
|
||||
|
||||
dep_wp = dependency('wayland-protocols', version: '>= 1.41',
|
||||
dep_wp = dependency('wayland-protocols', version: '>= 1.46',
|
||||
fallback: ['wayland-protocols', 'wayland_protocols'])
|
||||
dir_wp_base = dep_wp.get_variable(pkgconfig: 'pkgdatadir', internal: 'pkgdatadir')
|
||||
|
||||
|
|
@ -17,6 +17,7 @@ install_data(
|
|||
|
||||
generated_protocols = [
|
||||
[ 'color-management', 'staging', 'v1' ],
|
||||
[ 'color-representation', 'staging', 'v1' ],
|
||||
[ 'commit-timing', 'staging', 'v1' ],
|
||||
[ 'fifo', 'staging', 'v1' ],
|
||||
[ 'fullscreen-shell', 'unstable', 'v1' ],
|
||||
|
|
|
|||
326
tests/color-representation-common.c
Normal file
326
tests/color-representation-common.c
Normal file
|
|
@ -0,0 +1,326 @@
|
|||
/*
|
||||
* Copyright 2025 Collabora, Ltd.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the
|
||||
* next paragraph) shall be included in all copies or substantial
|
||||
* portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "color-representation-common.h"
|
||||
|
||||
#include "image-iter.h"
|
||||
#include "pixel-formats.h"
|
||||
#include "shared/weston-drm-fourcc.h"
|
||||
#include "xdg-client-helper.h"
|
||||
|
||||
static void
|
||||
presentation_feedback_handle_sync_output(void *data,
|
||||
struct wp_presentation_feedback *feedback,
|
||||
struct wl_output *output)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
presentation_feedback_handle_presented(void *data,
|
||||
struct wp_presentation_feedback *feedback,
|
||||
uint32_t tv_sec_hi,
|
||||
uint32_t tv_sec_lo,
|
||||
uint32_t tv_nsec,
|
||||
uint32_t refresh,
|
||||
uint32_t seq_hi,
|
||||
uint32_t seq_lo,
|
||||
uint32_t flags)
|
||||
{
|
||||
enum feedback_result *result = data;
|
||||
bool zero_copy = flags & WP_PRESENTATION_FEEDBACK_KIND_ZERO_COPY;
|
||||
|
||||
if (zero_copy)
|
||||
*result = FB_PRESENTED_ZERO_COPY;
|
||||
else
|
||||
*result = FB_PRESENTED;
|
||||
|
||||
wp_presentation_feedback_destroy(feedback);
|
||||
}
|
||||
|
||||
static void
|
||||
presentation_feedback_handle_discarded(void *data,
|
||||
struct wp_presentation_feedback *feedback)
|
||||
{
|
||||
enum feedback_result *result = data;
|
||||
|
||||
*result = FB_DISCARDED;
|
||||
wp_presentation_feedback_destroy(feedback);
|
||||
}
|
||||
|
||||
static const struct wp_presentation_feedback_listener presentation_feedback_listener = {
|
||||
.sync_output = presentation_feedback_handle_sync_output,
|
||||
.presented = presentation_feedback_handle_presented,
|
||||
.discarded = presentation_feedback_handle_discarded,
|
||||
};
|
||||
|
||||
static void
|
||||
presentation_wait_nofail(struct client *client, enum feedback_result *result)
|
||||
{
|
||||
while (*result == FB_PENDING) {
|
||||
if (!test_assert_int_ge(wl_display_dispatch(client->wl_display), 0))
|
||||
break;
|
||||
}
|
||||
test_assert_u64_ne(*result, FB_PENDING);
|
||||
}
|
||||
|
||||
static void
|
||||
x8r8g8b8_to_ycbcr8(uint32_t xrgb,
|
||||
const struct color_state *color_state,
|
||||
uint8_t *y_out, uint8_t *cb_out, uint8_t *cr_out)
|
||||
{
|
||||
double y, cb, cr;
|
||||
double r = (xrgb >> 16) & 0xff;
|
||||
double g = (xrgb >> 8) & 0xff;
|
||||
double b = (xrgb >> 0) & 0xff;
|
||||
|
||||
/* normalize to [0.0, 1.0] */
|
||||
r /= 255.0;
|
||||
g /= 255.0;
|
||||
b /= 255.0;
|
||||
|
||||
/* Y normalized to [0.0, 1.0], Cb and Cr [-0.5, 0.5] */
|
||||
switch ((int)color_state->coefficients) {
|
||||
case 0:
|
||||
case WP_COLOR_REPRESENTATION_SURFACE_V1_COEFFICIENTS_BT709:
|
||||
/* We choose BT709 as default */
|
||||
y = 0.2126 * r + 0.7152 * g + 0.0722 * b;
|
||||
cr = (r - y) / 1.5748;
|
||||
cb = (b - y) / 1.8556;
|
||||
break;
|
||||
case WP_COLOR_REPRESENTATION_SURFACE_V1_COEFFICIENTS_BT601:
|
||||
y = 0.299 * r + 0.587 * g + 0.114 * b;
|
||||
cr = (r - y) / 1.402;
|
||||
cb = (b - y) / 1.772;
|
||||
break;
|
||||
case WP_COLOR_REPRESENTATION_SURFACE_V1_COEFFICIENTS_BT2020:
|
||||
y = 0.2627 * r + 0.678 * g + 0.0593 * b;
|
||||
cr = (r - y) / 1.4746;
|
||||
cb = (b - y) / 1.8814;
|
||||
break;
|
||||
case WP_COLOR_REPRESENTATION_SURFACE_V1_COEFFICIENTS_IDENTITY:
|
||||
case WP_COLOR_REPRESENTATION_SURFACE_V1_COEFFICIENTS_FCC:
|
||||
/* For protocol error testing ensure we create invalid output */
|
||||
y = 0;
|
||||
cr = 0;
|
||||
cb = 0;
|
||||
break;
|
||||
default:
|
||||
test_assert_not_reached("Coefficients not handled");
|
||||
}
|
||||
|
||||
switch ((int)color_state->range) {
|
||||
case 0:
|
||||
case WP_COLOR_REPRESENTATION_SURFACE_V1_RANGE_LIMITED:
|
||||
/* We choose narrow range as default */
|
||||
*y_out = round(219.0 * y + 16.0);
|
||||
if (cr_out)
|
||||
*cr_out = round(224.0 * cr + 128.0);
|
||||
if (cb_out)
|
||||
*cb_out = round(224.0 * cb + 128.0);
|
||||
break;
|
||||
case WP_COLOR_REPRESENTATION_SURFACE_V1_RANGE_FULL:
|
||||
*y_out = round(255.0 * y);
|
||||
if (cr_out)
|
||||
*cr_out = round(255.0 * cr + 128.0);
|
||||
if (cb_out)
|
||||
*cb_out = round(255.0 * cb + 128.0);
|
||||
break;
|
||||
default:
|
||||
test_assert_not_reached("Range not handled");
|
||||
}
|
||||
}
|
||||
|
||||
static struct client_buffer*
|
||||
create_and_fill_nv12_buffer_with_cake(struct client *client,
|
||||
enum client_buffer_type buffer_type,
|
||||
const struct color_state *color_state)
|
||||
{
|
||||
const struct pixel_format_info *fmt_info;
|
||||
struct client_buffer *buffer;
|
||||
pixman_image_t *rgb_image;
|
||||
struct image_header src;
|
||||
uint8_t *y_base;
|
||||
uint16_t *uv_base;
|
||||
char *fname;
|
||||
int width, height;
|
||||
|
||||
fmt_info = pixel_format_get_info(DRM_FORMAT_NV12);
|
||||
width = height = 256;
|
||||
|
||||
switch (buffer_type) {
|
||||
case CLIENT_BUFFER_TYPE_SHM:
|
||||
buffer = client_buffer_util_create_shm_buffer(client->wl_shm,
|
||||
fmt_info,
|
||||
width,
|
||||
height);
|
||||
break;
|
||||
case CLIENT_BUFFER_TYPE_DMABUF:
|
||||
buffer = client_buffer_util_create_dmabuf_buffer(client->wl_display,
|
||||
client->dmabuf,
|
||||
fmt_info,
|
||||
width,
|
||||
height);
|
||||
break;
|
||||
default:
|
||||
test_assert_not_reached("Buffer type not handled");
|
||||
break;
|
||||
}
|
||||
|
||||
fname = image_filename("chocolate-cake");
|
||||
rgb_image = load_image_from_png(fname);
|
||||
free(fname);
|
||||
test_assert_ptr_not_null(rgb_image);
|
||||
|
||||
src = image_header_from(rgb_image);
|
||||
|
||||
y_base = buffer->data + buffer->offsets[0];
|
||||
uv_base = (uint16_t *)(buffer->data + buffer->offsets[1]);
|
||||
|
||||
client_buffer_util_maybe_sync_dmabuf_start(buffer);
|
||||
for (int y = 0; y < src.height; y++) {
|
||||
uint32_t *rgb_row;
|
||||
uint8_t *y_row;
|
||||
uint16_t *uv_row;
|
||||
|
||||
rgb_row = image_header_get_row_u32(&src, y / 2 * 2);
|
||||
y_row = y_base + y * buffer->strides[0];
|
||||
uv_row = uv_base + (y / 2) * (buffer->strides[1] / sizeof(uint16_t));
|
||||
|
||||
for (int x = 0; x < src.width; x++) {
|
||||
uint32_t argb;
|
||||
uint8_t cr;
|
||||
uint8_t cb;
|
||||
|
||||
/*
|
||||
* Sub-sample the source image instead, so that U and V
|
||||
* sub-sampling does not require proper
|
||||
* filtering/averaging/siting.
|
||||
*/
|
||||
argb = *(rgb_row + x / 2 * 2);
|
||||
|
||||
/*
|
||||
* A stupid way of "sub-sampling" chroma. This does not
|
||||
* do the necessary filtering/averaging/siting.
|
||||
*/
|
||||
if ((y & 1) == 0 && (x & 1) == 0) {
|
||||
x8r8g8b8_to_ycbcr8(argb, color_state, y_row + x,
|
||||
&cb, &cr);
|
||||
*(uv_row + x / 2) = ((uint16_t) cb) |
|
||||
((uint16_t) cr << 8);
|
||||
} else {
|
||||
x8r8g8b8_to_ycbcr8(argb, color_state, y_row + x,
|
||||
NULL, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
client_buffer_util_maybe_sync_dmabuf_end(buffer);
|
||||
|
||||
pixman_image_unref(rgb_image);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/*
|
||||
* Test that a fullscreen client with smaller-than-fullscreen-sized NV12 buffer
|
||||
* is correctly rendered with various YCbCr matrix coefficients and range
|
||||
* combinations.
|
||||
*/
|
||||
enum test_result_code
|
||||
test_color_representation(const struct color_state *color_state,
|
||||
enum client_buffer_type buffer_type,
|
||||
enum feedback_result expected_result)
|
||||
{
|
||||
struct xdg_client *xdg_client;
|
||||
struct client *client;
|
||||
struct xdg_surface_data *xdg_surface;
|
||||
struct wl_surface *surface;
|
||||
struct client_buffer *buffer;
|
||||
struct wp_presentation_feedback *presentation_feedback;
|
||||
struct wp_color_representation_surface_v1 *color_representation_surface = NULL;
|
||||
enum feedback_result result;
|
||||
struct buffer *screenshot;
|
||||
bool match;
|
||||
|
||||
xdg_client = create_xdg_client();
|
||||
client = xdg_client->client;
|
||||
xdg_surface = create_xdg_surface(xdg_client);
|
||||
surface = xdg_surface->surface->wl_surface;
|
||||
|
||||
xdg_surface_make_toplevel(xdg_surface,
|
||||
"weston.test.color-representation", "one");
|
||||
xdg_toplevel_set_fullscreen(xdg_surface->xdg_toplevel, NULL);
|
||||
xdg_surface_wait_configure(xdg_surface);
|
||||
|
||||
buffer = create_and_fill_nv12_buffer_with_cake(client, buffer_type,
|
||||
color_state);
|
||||
|
||||
wl_surface_attach(surface, buffer->wl_buffer, 0, 0);
|
||||
wl_surface_damage(surface, 0, 0, INT32_MAX, INT32_MAX);
|
||||
xdg_surface_maybe_ack_configure(xdg_surface);
|
||||
|
||||
if (color_state->create_color_representation_surface) {
|
||||
color_representation_surface =
|
||||
wp_color_representation_manager_v1_get_surface(
|
||||
client->color_representation, surface);
|
||||
if (color_state->coefficients != 0)
|
||||
wp_color_representation_surface_v1_set_coefficients_and_range(
|
||||
color_representation_surface,
|
||||
color_state->coefficients, color_state->range);
|
||||
}
|
||||
|
||||
result = FB_PENDING;
|
||||
presentation_feedback = wp_presentation_feedback(client->presentation,
|
||||
surface);
|
||||
wp_presentation_feedback_add_listener(presentation_feedback,
|
||||
&presentation_feedback_listener,
|
||||
&result);
|
||||
wl_surface_commit(surface);
|
||||
presentation_wait_nofail(client, &result);
|
||||
|
||||
test_assert_enum(result, expected_result);
|
||||
|
||||
screenshot = client_capture_output(client, client->output,
|
||||
WESTON_CAPTURE_V1_SOURCE_FRAMEBUFFER,
|
||||
CLIENT_BUFFER_TYPE_SHM);
|
||||
test_assert_ptr_not_null(screenshot);
|
||||
|
||||
client_buffer_util_maybe_sync_dmabuf_start(screenshot->buf);
|
||||
match = verify_image(screenshot->image, "color-representation", 0,
|
||||
NULL, 0);
|
||||
client_buffer_util_maybe_sync_dmabuf_end(screenshot->buf);
|
||||
|
||||
buffer_destroy(screenshot);
|
||||
if (color_representation_surface)
|
||||
wp_color_representation_surface_v1_destroy(color_representation_surface);
|
||||
client_buffer_util_destroy_buffer(buffer);
|
||||
destroy_xdg_surface(xdg_surface);
|
||||
xdg_client_destroy(xdg_client);
|
||||
|
||||
test_assert_true(match);
|
||||
|
||||
return RESULT_OK;
|
||||
}
|
||||
66
tests/color-representation-common.h
Normal file
66
tests/color-representation-common.h
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Copyright 2025 Collabora, Ltd.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the
|
||||
* next paragraph) shall be included in all copies or substantial
|
||||
* portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "weston-test-client-helper.h"
|
||||
|
||||
struct setup_args {
|
||||
struct fixture_metadata meta;
|
||||
enum weston_renderer_type renderer;
|
||||
enum client_buffer_type buffer_type;
|
||||
bool gl_force_import_yuv_fallback;
|
||||
};
|
||||
|
||||
struct color_state {
|
||||
bool create_color_representation_surface;
|
||||
enum wp_color_representation_surface_v1_coefficients coefficients;
|
||||
enum wp_color_representation_surface_v1_range range;
|
||||
};
|
||||
|
||||
static const struct color_state color_state_cases[] = {
|
||||
#define CRS(x) WP_COLOR_REPRESENTATION_SURFACE_V1_ ##x
|
||||
{ false, 0, 0 },
|
||||
{ true, 0, 0 },
|
||||
{ true, CRS(COEFFICIENTS_BT601), CRS(RANGE_LIMITED) },
|
||||
{ true, CRS(COEFFICIENTS_BT601), CRS(RANGE_FULL) },
|
||||
{ true, CRS(COEFFICIENTS_BT709), CRS(RANGE_LIMITED) },
|
||||
{ true, CRS(COEFFICIENTS_BT709), CRS(RANGE_FULL) },
|
||||
{ true, CRS(COEFFICIENTS_BT2020), CRS(RANGE_LIMITED) },
|
||||
{ true, CRS(COEFFICIENTS_BT2020), CRS(RANGE_FULL) },
|
||||
#undef CRS
|
||||
};
|
||||
|
||||
enum feedback_result {
|
||||
FB_PENDING = 0,
|
||||
FB_PRESENTED,
|
||||
FB_PRESENTED_ZERO_COPY,
|
||||
FB_DISCARDED
|
||||
};
|
||||
|
||||
enum test_result_code
|
||||
test_color_representation(const struct color_state *color_state,
|
||||
enum client_buffer_type buffer_type,
|
||||
enum feedback_result expected_result);
|
||||
74
tests/color-representation-drm-test.c
Normal file
74
tests/color-representation-drm-test.c
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* Copyright © 2025 Collabora, Ltd.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the
|
||||
* next paragraph) shall be included in all copies or substantial
|
||||
* portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "color-representation-common.h"
|
||||
|
||||
#include "image-iter.h"
|
||||
#include "pixel-formats.h"
|
||||
#include "shared/weston-drm-fourcc.h"
|
||||
#include "shared/xalloc.h"
|
||||
#include "weston-test-client-helper.h"
|
||||
#include "weston-test-assert.h"
|
||||
#include "xdg-client-helper.h"
|
||||
|
||||
static const struct setup_args my_setup_args[] = {
|
||||
{
|
||||
.meta.name = "GL - dmabuf renderer",
|
||||
.renderer = WESTON_RENDERER_GL,
|
||||
.buffer_type = CLIENT_BUFFER_TYPE_DMABUF,
|
||||
},
|
||||
};
|
||||
|
||||
static enum test_result_code
|
||||
fixture_setup(struct weston_test_harness *harness, const struct setup_args *arg)
|
||||
{
|
||||
struct compositor_setup setup;
|
||||
|
||||
compositor_setup_defaults(&setup);
|
||||
setup.backend = WESTON_BACKEND_DRM;
|
||||
setup.renderer = arg->renderer;
|
||||
setup.logging_scopes = "log,drm-backend";
|
||||
|
||||
/* Currently enforced by vkms. Set as a reminder for the future. */
|
||||
setup.width = 1024;
|
||||
setup.height = 768;
|
||||
|
||||
setup.test_quirks.required_capabilities = WESTON_CAP_COLOR_REP;
|
||||
setup.test_quirks.gl_force_import_yuv_fallback =
|
||||
arg->gl_force_import_yuv_fallback;
|
||||
|
||||
return weston_test_harness_execute_as_client(harness, &setup);
|
||||
}
|
||||
DECLARE_FIXTURE_SETUP_WITH_ARG(fixture_setup, my_setup_args, meta);
|
||||
|
||||
TEST_P(color_representation_drm, color_state_cases) {
|
||||
const struct color_state *color_state = data;
|
||||
const struct setup_args *args = &my_setup_args[get_test_fixture_index()];
|
||||
|
||||
return test_color_representation(color_state, args->buffer_type,
|
||||
FB_PRESENTED_ZERO_COPY);
|
||||
}
|
||||
291
tests/color-representation-protocol-test.c
Normal file
291
tests/color-representation-protocol-test.c
Normal file
|
|
@ -0,0 +1,291 @@
|
|||
/*
|
||||
* Copyright 2025 Collabora, Ltd.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the
|
||||
* next paragraph) shall be included in all copies or substantial
|
||||
* portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "pixel-formats.h"
|
||||
#include "shared/weston-drm-fourcc.h"
|
||||
#include "shared/xalloc.h"
|
||||
#include "weston-test-assert.h"
|
||||
#include "weston-test-client-helper.h"
|
||||
#include "weston-test-fixture-compositor.h"
|
||||
|
||||
static enum test_result_code
|
||||
fixture_setup(struct weston_test_harness *harness)
|
||||
{
|
||||
struct compositor_setup setup;
|
||||
|
||||
compositor_setup_defaults(&setup);
|
||||
setup.renderer = WESTON_RENDERER_GL;
|
||||
setup.test_quirks.required_capabilities = WESTON_CAP_COLOR_REP;
|
||||
|
||||
return weston_test_harness_execute_as_client(harness, &setup);
|
||||
}
|
||||
DECLARE_FIXTURE_SETUP(fixture_setup);
|
||||
|
||||
/*
|
||||
* Test that the SURFACE_EXISTS error is send by the compositor.
|
||||
*/
|
||||
TEST(color_presentation_protocol_surface_exists)
|
||||
{
|
||||
struct wp_color_representation_surface_v1 *color_representation_surface;
|
||||
struct wp_color_representation_surface_v1 *color_representation_surface_2;
|
||||
struct client *client;
|
||||
struct wl_surface *surface;
|
||||
|
||||
client = create_client();
|
||||
client->surface = create_test_surface(client);
|
||||
surface = client->surface->wl_surface;
|
||||
|
||||
color_representation_surface =
|
||||
wp_color_representation_manager_v1_get_surface(
|
||||
client->color_representation, surface);
|
||||
color_representation_surface_2 =
|
||||
wp_color_representation_manager_v1_get_surface(
|
||||
client->color_representation, surface);
|
||||
|
||||
expect_protocol_error(client,
|
||||
&wp_color_representation_manager_v1_interface,
|
||||
WP_COLOR_REPRESENTATION_MANAGER_V1_ERROR_SURFACE_EXISTS);
|
||||
|
||||
wp_color_representation_surface_v1_destroy(color_representation_surface);
|
||||
wp_color_representation_surface_v1_destroy(color_representation_surface_2);
|
||||
client_destroy(client);
|
||||
|
||||
return RESULT_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Test that a color representation can successfully be recreated after
|
||||
* destruction without e.g. triggering a SURFACE_EXISTS error.
|
||||
*/
|
||||
TEST(color_presentation_protocol_surface_recreate)
|
||||
{
|
||||
struct wp_color_representation_surface_v1 *color_representation_surface;
|
||||
struct wp_color_representation_surface_v1 *color_representation_surface_2;
|
||||
struct client *client;
|
||||
struct wl_surface *surface;
|
||||
|
||||
client = create_client();
|
||||
client->surface = create_test_surface(client);
|
||||
surface = client->surface->wl_surface;
|
||||
|
||||
color_representation_surface =
|
||||
wp_color_representation_manager_v1_get_surface(
|
||||
client->color_representation, surface);
|
||||
wp_color_representation_surface_v1_destroy(color_representation_surface);
|
||||
color_representation_surface_2 =
|
||||
wp_color_representation_manager_v1_get_surface(
|
||||
client->color_representation, surface);
|
||||
|
||||
client_roundtrip(client);
|
||||
|
||||
wp_color_representation_surface_v1_destroy(color_representation_surface_2);
|
||||
client_destroy(client);
|
||||
|
||||
return RESULT_OK;
|
||||
}
|
||||
|
||||
struct coefficients_case {
|
||||
uint32_t drm_format;
|
||||
enum wp_color_representation_surface_v1_coefficients coefficients;
|
||||
enum wp_color_representation_surface_v1_range range;
|
||||
enum wp_color_representation_surface_v1_error error_code;
|
||||
};
|
||||
|
||||
#define VALID_CASE(format, coefs, range) { \
|
||||
DRM_FORMAT_ ## format, \
|
||||
WP_COLOR_REPRESENTATION_SURFACE_V1_COEFFICIENTS_ ## coefs, \
|
||||
WP_COLOR_REPRESENTATION_SURFACE_V1_RANGE_ ## range, \
|
||||
0 \
|
||||
}
|
||||
|
||||
#define INVALID_CASE(format, coefs, range, err) { \
|
||||
DRM_FORMAT_ ## format, \
|
||||
WP_COLOR_REPRESENTATION_SURFACE_V1_COEFFICIENTS_ ## coefs, \
|
||||
WP_COLOR_REPRESENTATION_SURFACE_V1_RANGE_ ## range, \
|
||||
WP_COLOR_REPRESENTATION_SURFACE_V1_ERROR_ ## err \
|
||||
}
|
||||
|
||||
static const struct coefficients_case coefficients_cases[] = {
|
||||
VALID_CASE(ARGB8888, IDENTITY, FULL),
|
||||
INVALID_CASE(ARGB8888, IDENTITY, LIMITED, COEFFICIENTS),
|
||||
INVALID_CASE(ARGB8888, BT601, LIMITED, PIXEL_FORMAT),
|
||||
INVALID_CASE(ARGB8888, BT601, FULL, PIXEL_FORMAT),
|
||||
INVALID_CASE(ARGB8888, BT709, LIMITED, PIXEL_FORMAT),
|
||||
INVALID_CASE(ARGB8888, BT709, FULL, PIXEL_FORMAT),
|
||||
INVALID_CASE(ARGB8888, BT2020, LIMITED, PIXEL_FORMAT),
|
||||
INVALID_CASE(ARGB8888, BT2020, FULL, PIXEL_FORMAT),
|
||||
INVALID_CASE(ARGB8888, FCC, LIMITED, COEFFICIENTS),
|
||||
INVALID_CASE(ARGB8888, FCC, FULL, COEFFICIENTS),
|
||||
{DRM_FORMAT_ARGB8888, 0, 0, WP_COLOR_REPRESENTATION_SURFACE_V1_ERROR_COEFFICIENTS},
|
||||
VALID_CASE(NV12, BT601, LIMITED),
|
||||
VALID_CASE(NV12, BT601, FULL),
|
||||
VALID_CASE(NV12, BT709, LIMITED),
|
||||
VALID_CASE(NV12, BT709, FULL),
|
||||
VALID_CASE(NV12, BT2020, LIMITED),
|
||||
VALID_CASE(NV12, BT2020, FULL),
|
||||
INVALID_CASE(NV12, IDENTITY, LIMITED, COEFFICIENTS),
|
||||
INVALID_CASE(NV12, IDENTITY, FULL, PIXEL_FORMAT),
|
||||
INVALID_CASE(NV12, FCC, LIMITED, COEFFICIENTS),
|
||||
INVALID_CASE(NV12, FCC, FULL, COEFFICIENTS),
|
||||
{DRM_FORMAT_NV12, 0, 0, WP_COLOR_REPRESENTATION_SURFACE_V1_ERROR_COEFFICIENTS},
|
||||
};
|
||||
|
||||
/*
|
||||
* Test that various protocol errors regarding invalid combinations of DRM
|
||||
* format, matrix coefficients and quantization range are send by the compositor
|
||||
* as required by the protocol.
|
||||
*/
|
||||
TEST_P(color_presentation_protocol_valid_coefficients, coefficients_cases)
|
||||
{
|
||||
const struct coefficients_case *coefficients_case = data;
|
||||
struct wp_color_representation_surface_v1 *color_representation_surface;
|
||||
struct client *client;
|
||||
struct wl_surface *surface;
|
||||
|
||||
client = create_client();
|
||||
client->surface = create_test_surface(client);
|
||||
surface = client->surface->wl_surface;
|
||||
client->surface->buffer = create_shm_buffer(client, 8, 8,
|
||||
coefficients_case->drm_format);
|
||||
|
||||
wl_surface_attach(surface, client->surface->buffer->proxy, 0, 0);
|
||||
wl_surface_damage(surface, 0, 0, INT32_MAX, INT32_MAX);
|
||||
|
||||
color_representation_surface =
|
||||
wp_color_representation_manager_v1_get_surface(
|
||||
client->color_representation,
|
||||
surface);
|
||||
wp_color_representation_surface_v1_set_coefficients_and_range(
|
||||
color_representation_surface,
|
||||
coefficients_case->coefficients,
|
||||
coefficients_case->range);
|
||||
wl_surface_commit(surface);
|
||||
|
||||
if (coefficients_case->error_code)
|
||||
expect_protocol_error(client,
|
||||
&wp_color_representation_surface_v1_interface,
|
||||
coefficients_case->error_code);
|
||||
else
|
||||
client_roundtrip(client);
|
||||
|
||||
wp_color_representation_surface_v1_destroy(color_representation_surface);
|
||||
client_destroy(client);
|
||||
|
||||
return RESULT_OK;
|
||||
}
|
||||
|
||||
struct alpha_mode_case {
|
||||
enum wp_color_representation_surface_v1_alpha_mode alpha_mode;
|
||||
enum wp_color_representation_surface_v1_error error_code;
|
||||
};
|
||||
|
||||
static const struct alpha_mode_case alpha_mode_cases[] = {
|
||||
{WP_COLOR_REPRESENTATION_SURFACE_V1_ALPHA_MODE_PREMULTIPLIED_ELECTRICAL, 0},
|
||||
{WP_COLOR_REPRESENTATION_SURFACE_V1_ALPHA_MODE_PREMULTIPLIED_OPTICAL, WP_COLOR_REPRESENTATION_SURFACE_V1_ERROR_ALPHA_MODE},
|
||||
{WP_COLOR_REPRESENTATION_SURFACE_V1_ALPHA_MODE_STRAIGHT, WP_COLOR_REPRESENTATION_SURFACE_V1_ERROR_ALPHA_MODE},
|
||||
{-1, WP_COLOR_REPRESENTATION_SURFACE_V1_ERROR_ALPHA_MODE},
|
||||
};
|
||||
|
||||
/*
|
||||
* Test that PREMULTIPLIED_ELECTRICAL is the only alpha mode currently supported.
|
||||
*/
|
||||
TEST_P(color_presentation_protocol_alpha_mode, alpha_mode_cases)
|
||||
{
|
||||
const struct alpha_mode_case *alpha_mode_case = data;
|
||||
struct wp_color_representation_surface_v1 *color_representation_surface;
|
||||
struct client *client;
|
||||
|
||||
client = create_client();
|
||||
client->surface = create_test_surface(client);
|
||||
|
||||
color_representation_surface =
|
||||
wp_color_representation_manager_v1_get_surface(
|
||||
client->color_representation,
|
||||
client->surface->wl_surface);
|
||||
wp_color_representation_surface_v1_set_alpha_mode(color_representation_surface,
|
||||
alpha_mode_case->alpha_mode);
|
||||
|
||||
if (alpha_mode_case->error_code)
|
||||
expect_protocol_error(client,
|
||||
&wp_color_representation_surface_v1_interface,
|
||||
alpha_mode_case->error_code);
|
||||
else
|
||||
client_roundtrip(client);
|
||||
|
||||
wp_color_representation_surface_v1_destroy(color_representation_surface);
|
||||
client_destroy(client);
|
||||
|
||||
return RESULT_OK;
|
||||
}
|
||||
|
||||
struct chroma_location_case {
|
||||
enum wp_color_representation_surface_v1_chroma_location chroma_location;
|
||||
enum wp_color_representation_surface_v1_error error_code;
|
||||
};
|
||||
|
||||
static const struct chroma_location_case chroma_location_cases[] = {
|
||||
{WP_COLOR_REPRESENTATION_SURFACE_V1_CHROMA_LOCATION_TYPE_0, 0},
|
||||
{WP_COLOR_REPRESENTATION_SURFACE_V1_CHROMA_LOCATION_TYPE_1, 0},
|
||||
{WP_COLOR_REPRESENTATION_SURFACE_V1_CHROMA_LOCATION_TYPE_2, 0},
|
||||
{WP_COLOR_REPRESENTATION_SURFACE_V1_CHROMA_LOCATION_TYPE_3, 0},
|
||||
{WP_COLOR_REPRESENTATION_SURFACE_V1_CHROMA_LOCATION_TYPE_4, 0},
|
||||
{WP_COLOR_REPRESENTATION_SURFACE_V1_CHROMA_LOCATION_TYPE_5, 0},
|
||||
{0, WP_COLOR_REPRESENTATION_SURFACE_V1_ERROR_CHROMA_LOCATION},
|
||||
};
|
||||
|
||||
/*
|
||||
* Test that all chroma location values are accepted, but not invalid values.
|
||||
*/
|
||||
TEST_P(color_presentation_protocol_chroma_location, chroma_location_cases)
|
||||
{
|
||||
const struct chroma_location_case *chroma_location_case = data;
|
||||
struct wp_color_representation_surface_v1 *color_representation_surface;
|
||||
struct client *client;
|
||||
|
||||
client = create_client();
|
||||
client->surface = create_test_surface(client);
|
||||
|
||||
color_representation_surface =
|
||||
wp_color_representation_manager_v1_get_surface(
|
||||
client->color_representation,
|
||||
client->surface->wl_surface);
|
||||
wp_color_representation_surface_v1_set_chroma_location(
|
||||
color_representation_surface,
|
||||
chroma_location_case->chroma_location);
|
||||
|
||||
if (chroma_location_case->error_code)
|
||||
expect_protocol_error(client,
|
||||
&wp_color_representation_surface_v1_interface,
|
||||
chroma_location_case->error_code);
|
||||
else
|
||||
client_roundtrip(client);
|
||||
|
||||
wp_color_representation_surface_v1_destroy(color_representation_surface);
|
||||
client_destroy(client);
|
||||
|
||||
return RESULT_OK;
|
||||
}
|
||||
250
tests/color-representation-renderer-test.c
Normal file
250
tests/color-representation-renderer-test.c
Normal file
|
|
@ -0,0 +1,250 @@
|
|||
/*
|
||||
* Copyright 2025 Collabora, Ltd.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the
|
||||
* next paragraph) shall be included in all copies or substantial
|
||||
* portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "color-representation-common.h"
|
||||
|
||||
#include "pixel-formats.h"
|
||||
#include "shared/weston-drm-fourcc.h"
|
||||
#include "weston-test-assert.h"
|
||||
#include "xdg-client-helper.h"
|
||||
|
||||
static const struct setup_args my_setup_args[] = {
|
||||
{
|
||||
.meta.name = "GL - shm",
|
||||
.renderer = WESTON_RENDERER_GL,
|
||||
.buffer_type = CLIENT_BUFFER_TYPE_SHM,
|
||||
},
|
||||
{
|
||||
.meta.name = "GL - dmabuf renderer",
|
||||
.renderer = WESTON_RENDERER_GL,
|
||||
.buffer_type = CLIENT_BUFFER_TYPE_DMABUF,
|
||||
},
|
||||
{
|
||||
.meta.name = "GL - dmabuf renderer + force-import-yuv-fallback",
|
||||
.renderer = WESTON_RENDERER_GL,
|
||||
.buffer_type = CLIENT_BUFFER_TYPE_DMABUF,
|
||||
.gl_force_import_yuv_fallback = true,
|
||||
},
|
||||
};
|
||||
|
||||
static enum test_result_code
|
||||
fixture_setup(struct weston_test_harness *harness, const struct setup_args *arg)
|
||||
{
|
||||
struct compositor_setup setup;
|
||||
|
||||
compositor_setup_defaults(&setup);
|
||||
setup.renderer = arg->renderer;
|
||||
setup.refresh = HIGHEST_OUTPUT_REFRESH;
|
||||
setup.logging_scopes = "log";
|
||||
|
||||
/* Required for test that also run on DRM */
|
||||
setup.width = 1024;
|
||||
setup.height = 768;
|
||||
|
||||
setup.test_quirks.required_capabilities = WESTON_CAP_COLOR_REP;
|
||||
setup.test_quirks.gl_force_import_yuv_fallback =
|
||||
arg->gl_force_import_yuv_fallback;
|
||||
|
||||
return weston_test_harness_execute_as_client(harness, &setup);
|
||||
}
|
||||
DECLARE_FIXTURE_SETUP_WITH_ARG(fixture_setup, my_setup_args, meta);
|
||||
|
||||
TEST_P(color_representation_renderer, color_state_cases) {
|
||||
const struct color_state *color_state = data;
|
||||
const struct setup_args *args = &my_setup_args[get_test_fixture_index()];
|
||||
|
||||
return test_color_representation(color_state, args->buffer_type,
|
||||
FB_PRESENTED);
|
||||
}
|
||||
|
||||
static struct client_buffer*
|
||||
create_and_fill_nv12_buffer(struct client *client,
|
||||
enum client_buffer_type buffer_type, int width,
|
||||
int height)
|
||||
{
|
||||
const struct pixel_format_info *fmt_info;
|
||||
struct client_buffer *buffer;
|
||||
uint8_t *y_base;
|
||||
uint16_t *uv_base;
|
||||
|
||||
fmt_info = pixel_format_get_info(DRM_FORMAT_NV12);
|
||||
|
||||
switch (buffer_type) {
|
||||
case CLIENT_BUFFER_TYPE_SHM:
|
||||
buffer = client_buffer_util_create_shm_buffer(client->wl_shm,
|
||||
fmt_info,
|
||||
width,
|
||||
height);
|
||||
break;
|
||||
case CLIENT_BUFFER_TYPE_DMABUF:
|
||||
buffer = client_buffer_util_create_dmabuf_buffer(client->wl_display,
|
||||
client->dmabuf,
|
||||
fmt_info,
|
||||
width,
|
||||
height);
|
||||
break;
|
||||
default:
|
||||
test_assert_not_reached("Buffer type not handled");
|
||||
break;
|
||||
}
|
||||
|
||||
y_base = buffer->data + buffer->offsets[0];
|
||||
uv_base = (uint16_t *)(buffer->data + buffer->offsets[1]);
|
||||
|
||||
client_buffer_util_maybe_sync_dmabuf_start(buffer);
|
||||
for (int y = 0; y < height; y++) {
|
||||
uint8_t *y_row;
|
||||
uint16_t *uv_row;
|
||||
|
||||
y_row = y_base + y * buffer->strides[0];
|
||||
uv_row = uv_base + (y / 2) * (buffer->strides[1] / sizeof(uint16_t));
|
||||
|
||||
for (int x = 0; x < width; x++) {
|
||||
*(y_row + x) = 0x30;
|
||||
*(uv_row + x / 2) = 0x5050;
|
||||
}
|
||||
}
|
||||
client_buffer_util_maybe_sync_dmabuf_end(buffer);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static void
|
||||
buffer_release(void *data, struct wl_buffer *buffer)
|
||||
{
|
||||
wl_buffer_destroy(buffer);
|
||||
}
|
||||
|
||||
static const struct wl_buffer_listener buffer_listener = {
|
||||
buffer_release
|
||||
};
|
||||
|
||||
/*
|
||||
* Test that the same NV12 buffer can be attached to multiple wl_surfaces with
|
||||
* different color representation values.
|
||||
*/
|
||||
TEST(drm_color_representation_reuse_buffer)
|
||||
{
|
||||
const struct setup_args *args = &my_setup_args[get_test_fixture_index()];
|
||||
struct xdg_client *xdg_client;
|
||||
struct client *client;
|
||||
struct xdg_surface_data *xdg_surface;
|
||||
struct wl_surface *toplevel_surface;
|
||||
int n_color_state_cases = ARRAY_LENGTH(color_state_cases);
|
||||
struct wl_surface *surface[n_color_state_cases];
|
||||
struct wl_subsurface *subsurface[n_color_state_cases];
|
||||
struct wl_buffer *toplevel_buffer;
|
||||
struct client_buffer *buffer;
|
||||
struct wp_viewport *toplevel_viewport;
|
||||
struct wp_color_representation_surface_v1 *color_representation_surface[n_color_state_cases];
|
||||
struct rectangle clip = { .width = 128, .height = 128 };
|
||||
bool match;
|
||||
|
||||
xdg_client = create_xdg_client();
|
||||
client = xdg_client->client;
|
||||
xdg_surface = create_xdg_surface(xdg_client);
|
||||
toplevel_surface = xdg_surface->surface->wl_surface;
|
||||
|
||||
xdg_surface_make_toplevel(xdg_surface,
|
||||
"weston.test.color-representation", "one");
|
||||
xdg_toplevel_set_fullscreen(xdg_surface->xdg_toplevel, NULL);
|
||||
xdg_surface_wait_configure(xdg_surface);
|
||||
|
||||
toplevel_viewport = wp_viewporter_get_viewport(client->viewporter,
|
||||
toplevel_surface);
|
||||
wp_viewport_set_destination(toplevel_viewport,
|
||||
xdg_surface->configure.width, xdg_surface->configure.height);
|
||||
toplevel_buffer =
|
||||
wp_single_pixel_buffer_manager_v1_create_u32_rgba_buffer(client->single_pixel_manager,
|
||||
0x0, 0x0, 0x0, 0x0);
|
||||
wl_surface_attach(toplevel_surface, toplevel_buffer, 0, 0);
|
||||
wl_buffer_add_listener(toplevel_buffer, &buffer_listener, NULL);
|
||||
wl_surface_damage_buffer(toplevel_surface, 0, 0, 1, 1);
|
||||
|
||||
buffer = create_and_fill_nv12_buffer(client, args->buffer_type,
|
||||
clip.width / 4, clip.height / 2 - 4);
|
||||
|
||||
for (int i = 0; i < n_color_state_cases; i++) {
|
||||
surface[i] = wl_compositor_create_surface(client->wl_compositor);
|
||||
subsurface[i] =
|
||||
wl_subcompositor_get_subsurface(client->wl_subcompositor,
|
||||
surface[i], toplevel_surface);
|
||||
}
|
||||
|
||||
wl_subsurface_set_position(subsurface[0], 0, 4);
|
||||
wl_subsurface_set_position(subsurface[1], 0, clip.height / 2);
|
||||
wl_subsurface_set_position(subsurface[2], clip.width / 4, 4);
|
||||
wl_subsurface_set_position(subsurface[3], clip.width / 4,
|
||||
clip.height / 2);
|
||||
wl_subsurface_set_position(subsurface[4], clip.width / 4 * 2, 4);
|
||||
wl_subsurface_set_position(subsurface[5], clip.width / 4 * 2,
|
||||
clip.height / 2);
|
||||
wl_subsurface_set_position(subsurface[6], clip.width / 4 * 3, 4);
|
||||
wl_subsurface_set_position(subsurface[7], clip.width / 4 * 3,
|
||||
clip.height / 2);
|
||||
|
||||
for (int i = 0; i < n_color_state_cases; i++) {
|
||||
if (color_state_cases[i].create_color_representation_surface) {
|
||||
color_representation_surface[i] =
|
||||
wp_color_representation_manager_v1_get_surface(
|
||||
client->color_representation,
|
||||
surface[i]);
|
||||
if (color_state_cases[i].coefficients != 0)
|
||||
wp_color_representation_surface_v1_set_coefficients_and_range(
|
||||
color_representation_surface[i],
|
||||
color_state_cases[i].coefficients,
|
||||
color_state_cases[i].range);
|
||||
} else {
|
||||
color_representation_surface[i] = NULL;
|
||||
}
|
||||
|
||||
wl_surface_attach(surface[i], buffer->wl_buffer, 0, 0);
|
||||
wl_surface_damage(surface[i], 0, 0, INT32_MAX, INT32_MAX);
|
||||
wl_surface_commit(surface[i]);
|
||||
}
|
||||
|
||||
xdg_surface_maybe_ack_configure(xdg_surface);
|
||||
wl_surface_commit(toplevel_surface);
|
||||
|
||||
match = verify_screen_content(client, "color-representation", 1,
|
||||
&clip, 0, NULL, NO_DECORATIONS);
|
||||
|
||||
for (int i = 0; i < n_color_state_cases; i++) {
|
||||
if (color_representation_surface[i])
|
||||
wp_color_representation_surface_v1_destroy(color_representation_surface[i]);
|
||||
wl_subsurface_destroy(subsurface[i]);
|
||||
wl_surface_destroy(surface[i]);
|
||||
}
|
||||
wp_viewport_destroy(toplevel_viewport);
|
||||
client_buffer_util_destroy_buffer(buffer);
|
||||
destroy_xdg_surface(xdg_surface);
|
||||
xdg_client_destroy(xdg_client);
|
||||
|
||||
test_assert_true(match);
|
||||
|
||||
return RESULT_OK;
|
||||
}
|
||||
|
|
@ -30,7 +30,9 @@ lib_test_client = static_library(
|
|||
[
|
||||
'weston-test-client-helper.c',
|
||||
'weston-test-fixture-compositor.c',
|
||||
'xdg-client-helper.c',
|
||||
'xdg-client-helper.c',
|
||||
color_representation_v1_client_protocol_h,
|
||||
color_representation_v1_protocol_c,
|
||||
commit_timing_v1_client_protocol_h,
|
||||
commit_timing_v1_protocol_c,
|
||||
fifo_v1_client_protocol_h,
|
||||
|
|
@ -140,6 +142,22 @@ tests = [
|
|||
dep_libdisplay_info,
|
||||
],
|
||||
},
|
||||
{ 'name': 'color-representation-drm',
|
||||
'sources': [
|
||||
'color-representation-common.c',
|
||||
'color-representation-common.h',
|
||||
'color-representation-drm-test.c',
|
||||
],
|
||||
'run_exclusive': true
|
||||
},
|
||||
{ 'name': 'color-representation-renderer',
|
||||
'sources': [
|
||||
'color-representation-common.c',
|
||||
'color-representation-common.h',
|
||||
'color-representation-renderer-test.c',
|
||||
],
|
||||
},
|
||||
{ 'name': 'color-representation-protocol', },
|
||||
{ 'name': 'commit-timing', },
|
||||
{ 'name': 'config-parser', },
|
||||
{
|
||||
|
|
|
|||
BIN
tests/reference/color-representation-00.png
Normal file
BIN
tests/reference/color-representation-00.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 49 KiB |
BIN
tests/reference/color-representation-01.png
Normal file
BIN
tests/reference/color-representation-01.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 393 B |
|
|
@ -59,6 +59,11 @@ struct drm_format {
|
|||
uint64_t modifier;
|
||||
};
|
||||
|
||||
struct coefficients_and_range {
|
||||
enum wp_color_representation_surface_v1_coefficients coefficients;
|
||||
enum wp_color_representation_surface_v1_range range;
|
||||
};
|
||||
|
||||
int
|
||||
surface_contains(struct surface *surface, int x, int y)
|
||||
{
|
||||
|
|
@ -638,6 +643,54 @@ static const struct zwp_linux_dmabuf_v1_listener dmabuf_listener = {
|
|||
dmabuf_modifier
|
||||
};
|
||||
|
||||
bool
|
||||
support_coefficients_and_range(struct client *client,
|
||||
enum wp_color_representation_surface_v1_coefficients coefficients,
|
||||
enum wp_color_representation_surface_v1_range range)
|
||||
{
|
||||
struct coefficients_and_range *p;
|
||||
|
||||
wl_array_for_each(p, &client->coefficients_and_ranges)
|
||||
if (p->coefficients == coefficients && p->range == range)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void
|
||||
color_representation_supported_alpha_mode(void *data,
|
||||
struct wp_color_representation_manager_v1 *wp_color_representation_manager_v1,
|
||||
uint32_t alpha_mode)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
color_representation_supported_coefficients_and_ranges(void *data,
|
||||
struct wp_color_representation_manager_v1 *wp_color_representation_manager_v1,
|
||||
uint32_t coefficients,
|
||||
uint32_t range)
|
||||
{
|
||||
struct client *client = data;
|
||||
struct coefficients_and_range *p;
|
||||
|
||||
p = wl_array_add(&client->coefficients_and_ranges, sizeof *p);
|
||||
assert(p);
|
||||
p->coefficients = coefficients;
|
||||
p->range = range;
|
||||
}
|
||||
|
||||
static void
|
||||
color_representation_done(void *data,
|
||||
struct wp_color_representation_manager_v1 *wp_color_representation_manager_v1)
|
||||
{
|
||||
}
|
||||
|
||||
static const struct wp_color_representation_manager_v1_listener color_representation_listener = {
|
||||
.supported_alpha_mode = color_representation_supported_alpha_mode,
|
||||
.supported_coefficients_and_ranges = color_representation_supported_coefficients_and_ranges,
|
||||
.done = color_representation_done,
|
||||
};
|
||||
|
||||
static void
|
||||
test_handle_pointer_position(void *data, struct weston_test *weston_test,
|
||||
wl_fixed_t x, wl_fixed_t y)
|
||||
|
|
@ -918,6 +971,13 @@ handle_global(void *data, struct wl_registry *registry,
|
|||
wl_registry_bind(registry, id,
|
||||
&wp_single_pixel_buffer_manager_v1_interface,
|
||||
1);
|
||||
} else if (strcmp(interface, wp_color_representation_manager_v1_interface.name) == 0) {
|
||||
client->color_representation =
|
||||
wl_registry_bind(registry, id,
|
||||
&wp_color_representation_manager_v1_interface, version);
|
||||
wp_color_representation_manager_v1_add_listener (client->color_representation,
|
||||
&color_representation_listener,
|
||||
client);
|
||||
} else if (strcmp(interface, "wl_output") == 0) {
|
||||
output = xzalloc(sizeof *output);
|
||||
output->wl_output =
|
||||
|
|
@ -1107,6 +1167,7 @@ create_client(void)
|
|||
test_assert_ptr_not_null(client->wl_display);
|
||||
wl_array_init(&client->shm_formats);
|
||||
wl_array_init(&client->drm_formats);
|
||||
wl_array_init(&client->coefficients_and_ranges);
|
||||
wl_list_init(&client->global_list);
|
||||
wl_list_init(&client->inputs);
|
||||
wl_list_init(&client->output_list);
|
||||
|
|
@ -1220,6 +1281,7 @@ client_destroy(struct client *client)
|
|||
|
||||
wl_array_release(&client->shm_formats);
|
||||
wl_array_release(&client->drm_formats);
|
||||
wl_array_release(&client->coefficients_and_ranges);
|
||||
|
||||
while (!wl_list_empty(&client->inputs)) {
|
||||
input_destroy(container_of(client->inputs.next,
|
||||
|
|
@ -1251,6 +1313,8 @@ client_destroy(struct client *client)
|
|||
wp_presentation_destroy(client->presentation);
|
||||
if (client->single_pixel_manager)
|
||||
wp_single_pixel_buffer_manager_v1_destroy(client->single_pixel_manager);
|
||||
if (client->color_representation)
|
||||
wp_color_representation_manager_v1_destroy(client->color_representation);
|
||||
if (client->wl_compositor)
|
||||
wl_compositor_destroy(client->wl_compositor);
|
||||
if (client->wl_subcompositor)
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
#include <pixman.h>
|
||||
|
||||
#include <wayland-client-protocol.h>
|
||||
#include "color-representation-v1-client-protocol.h"
|
||||
#include "linux-dmabuf-unstable-v1-client-protocol.h"
|
||||
#include "presentation-time-client-protocol.h"
|
||||
#include "shared/client-buffer-util.h"
|
||||
|
|
@ -64,6 +65,7 @@ struct client {
|
|||
struct wp_presentation *presentation;
|
||||
struct wp_single_pixel_buffer_manager_v1 *single_pixel_manager;
|
||||
struct wp_viewporter *viewporter;
|
||||
struct wp_color_representation_manager_v1 *color_representation;
|
||||
|
||||
struct test *test;
|
||||
struct wp_fifo_manager_v1 *fifo_manager;
|
||||
|
|
@ -80,6 +82,7 @@ struct client {
|
|||
struct surface *surface;
|
||||
struct wl_array shm_formats;
|
||||
struct wl_array drm_formats;
|
||||
struct wl_array coefficients_and_ranges;
|
||||
struct wl_list global_list;
|
||||
struct wl_list output_list; /* struct output::link */
|
||||
|
||||
|
|
@ -258,6 +261,11 @@ create_shm_buffer_solid(struct client *client, int width, int height,
|
|||
bool
|
||||
support_drm_format(struct client *client, uint32_t format, uint64_t modifier);
|
||||
|
||||
bool
|
||||
support_coefficients_and_range(struct client *client,
|
||||
enum wp_color_representation_surface_v1_coefficients coefficients,
|
||||
enum wp_color_representation_surface_v1_range range);
|
||||
|
||||
void
|
||||
buffer_destroy(struct buffer *buf);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue