mirror of
https://gitlab.freedesktop.org/wayland/weston.git
synced 2025-12-20 05:50:10 +01:00
tests: add color-output-parsing
This tests the [output] section key 'color-profile', which is meant for setting up parametric color profiles. It tests the special names, and fetching values from EDID. There are also tests for all accepted keys in a [color-profile] section. These tests are all positive. Error messages are tested in another patch. The test client helper changes are needed for loading the EDID file. Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
This commit is contained in:
parent
d00b758cee
commit
a06ef0f8aa
9 changed files with 757 additions and 2 deletions
|
|
@ -1944,7 +1944,7 @@ wet_parse_auto_profile(struct weston_output *output,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct weston_color_profile *
|
WESTON_EXPORT_FOR_TESTS struct weston_color_profile *
|
||||||
wet_create_output_color_profile(struct weston_output *output,
|
wet_create_output_color_profile(struct weston_output *output,
|
||||||
struct weston_config *wc,
|
struct weston_config *wc,
|
||||||
const char *prof_name)
|
const char *prof_name)
|
||||||
|
|
|
||||||
|
|
@ -53,3 +53,8 @@ wet_output_set_colorimetry_mode(struct weston_output *output,
|
||||||
|
|
||||||
typedef void (*wet_head_additional_setup)(struct weston_head *head,
|
typedef void (*wet_head_additional_setup)(struct weston_head *head,
|
||||||
struct weston_head *head_to_mirror);
|
struct weston_head *head_to_mirror);
|
||||||
|
|
||||||
|
struct weston_color_profile *
|
||||||
|
wet_create_output_color_profile(struct weston_output *output,
|
||||||
|
struct weston_config *wc,
|
||||||
|
const char *prof_name);
|
||||||
|
|
|
||||||
654
tests/color-output-parsing-test.c
Normal file
654
tests/color-output-parsing-test.c
Normal file
|
|
@ -0,0 +1,654 @@
|
||||||
|
/*
|
||||||
|
* 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 <libdisplay-info/info.h>
|
||||||
|
|
||||||
|
#include "weston-test-client-helper.h"
|
||||||
|
#include "weston-test-assert.h"
|
||||||
|
|
||||||
|
#include "weston-private.h"
|
||||||
|
#include "backend.h"
|
||||||
|
#include "color.h"
|
||||||
|
#include "color-properties.h"
|
||||||
|
#include "id-number-allocator.h"
|
||||||
|
#include "shared/string-helpers.h"
|
||||||
|
#include "shared/xalloc.h"
|
||||||
|
|
||||||
|
struct expected_params {
|
||||||
|
struct weston_color_profile_params template;
|
||||||
|
|
||||||
|
/* Cannot statically initialize these in the template: */
|
||||||
|
enum weston_transfer_function tf;
|
||||||
|
enum weston_color_primaries named_prim;
|
||||||
|
bool use_named_prim;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct config_testcase {
|
||||||
|
enum weston_eotf_mode eotf_mode;
|
||||||
|
enum weston_colorimetry_mode colorimetry_mode;
|
||||||
|
const char *profile_name;
|
||||||
|
const char *profile_string;
|
||||||
|
|
||||||
|
const struct expected_params expected;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define NO_VALUE -1.f
|
||||||
|
#define D65 { 0.3127f, 0.3290f }
|
||||||
|
#define prim_bt709 ((struct weston_color_gamut){ \
|
||||||
|
.primary = { \
|
||||||
|
{ 0.640f, 0.330f }, \
|
||||||
|
{ 0.300f, 0.600f }, \
|
||||||
|
{ 0.150f, 0.060f }, \
|
||||||
|
}, \
|
||||||
|
.white_point = D65, \
|
||||||
|
})
|
||||||
|
#define prim_bt2020 ((struct weston_color_gamut){ \
|
||||||
|
.primary = { \
|
||||||
|
{ 0.708f, 0.292f }, \
|
||||||
|
{ 0.170f, 0.797f }, \
|
||||||
|
{ 0.131f, 0.046f }, \
|
||||||
|
}, \
|
||||||
|
.white_point = D65, \
|
||||||
|
})
|
||||||
|
#define prim_display_p3 ((struct weston_color_gamut){ \
|
||||||
|
.primary = { \
|
||||||
|
{ 0.680f, 0.320f }, \
|
||||||
|
{ 0.265f, 0.690f }, \
|
||||||
|
{ 0.150f, 0.060f }, \
|
||||||
|
}, \
|
||||||
|
.white_point = D65, \
|
||||||
|
})
|
||||||
|
#define prim_hp_5dq99aa ((struct weston_color_gamut){ \
|
||||||
|
.primary = { \
|
||||||
|
{ 0.6650f, 0.3261f }, \
|
||||||
|
{ 0.2890f, 0.6435f }, \
|
||||||
|
{ 0.1494f, 0.0507f }, \
|
||||||
|
}, \
|
||||||
|
.white_point = { 0.3134f, 0.3291f }, \
|
||||||
|
})
|
||||||
|
|
||||||
|
static const struct config_testcase config_cases[] = {
|
||||||
|
{
|
||||||
|
WESTON_EOTF_MODE_SDR, WESTON_COLORIMETRY_MODE_DEFAULT,
|
||||||
|
"auto:",
|
||||||
|
"",
|
||||||
|
{
|
||||||
|
.template = {
|
||||||
|
.primaries = prim_bt709,
|
||||||
|
.target_primaries = prim_bt709,
|
||||||
|
.min_luminance = 0.2f,
|
||||||
|
.max_luminance = 80.f,
|
||||||
|
.reference_white_luminance = 80.f,
|
||||||
|
.target_min_luminance = 0.2f,
|
||||||
|
.target_max_luminance = 80.f,
|
||||||
|
.maxCLL = NO_VALUE,
|
||||||
|
.maxFALL = NO_VALUE,
|
||||||
|
},
|
||||||
|
.tf = WESTON_TF_GAMMA22,
|
||||||
|
.named_prim = WESTON_PRIMARIES_CICP_SRGB,
|
||||||
|
.use_named_prim = true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
WESTON_EOTF_MODE_TRADITIONAL_HDR, WESTON_COLORIMETRY_MODE_DEFAULT,
|
||||||
|
"auto:",
|
||||||
|
"",
|
||||||
|
{
|
||||||
|
.template = {
|
||||||
|
.primaries = prim_bt709,
|
||||||
|
.target_primaries = prim_bt709,
|
||||||
|
.min_luminance = 0.2f,
|
||||||
|
.max_luminance = 80.f,
|
||||||
|
.reference_white_luminance = 80.f,
|
||||||
|
.target_min_luminance = 0.2f,
|
||||||
|
.target_max_luminance = 80.f,
|
||||||
|
.maxCLL = NO_VALUE,
|
||||||
|
.maxFALL = NO_VALUE,
|
||||||
|
},
|
||||||
|
.tf = WESTON_TF_GAMMA22,
|
||||||
|
.named_prim = WESTON_PRIMARIES_CICP_SRGB,
|
||||||
|
.use_named_prim = true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
WESTON_EOTF_MODE_ST2084, WESTON_COLORIMETRY_MODE_DEFAULT,
|
||||||
|
"auto:",
|
||||||
|
"",
|
||||||
|
{
|
||||||
|
.template = {
|
||||||
|
.primaries = prim_bt709,
|
||||||
|
.target_primaries = prim_bt709,
|
||||||
|
.min_luminance = 0.005f,
|
||||||
|
.max_luminance = 10000.f,
|
||||||
|
.reference_white_luminance = 203.f,
|
||||||
|
.target_min_luminance = 0.005f,
|
||||||
|
.target_max_luminance = 10000.f,
|
||||||
|
.maxCLL = NO_VALUE,
|
||||||
|
.maxFALL = NO_VALUE,
|
||||||
|
},
|
||||||
|
.tf = WESTON_TF_ST2084_PQ,
|
||||||
|
.named_prim = WESTON_PRIMARIES_CICP_SRGB,
|
||||||
|
.use_named_prim = true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
WESTON_EOTF_MODE_HLG, WESTON_COLORIMETRY_MODE_DEFAULT,
|
||||||
|
"auto:",
|
||||||
|
"",
|
||||||
|
{
|
||||||
|
.template = {
|
||||||
|
.primaries = prim_bt709,
|
||||||
|
.target_primaries = prim_bt709,
|
||||||
|
.min_luminance = 0.005f,
|
||||||
|
.max_luminance = 1000.f,
|
||||||
|
.reference_white_luminance = 203.f,
|
||||||
|
.target_min_luminance = 0.005f,
|
||||||
|
.target_max_luminance = 1000.f,
|
||||||
|
.maxCLL = NO_VALUE,
|
||||||
|
.maxFALL = NO_VALUE,
|
||||||
|
},
|
||||||
|
.tf = WESTON_TF_HLG,
|
||||||
|
.named_prim = WESTON_PRIMARIES_CICP_SRGB,
|
||||||
|
.use_named_prim = true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
WESTON_EOTF_MODE_SDR, WESTON_COLORIMETRY_MODE_BT2020_RGB,
|
||||||
|
"auto:",
|
||||||
|
"",
|
||||||
|
{
|
||||||
|
.template = {
|
||||||
|
.primaries = prim_bt2020,
|
||||||
|
.target_primaries = prim_bt2020,
|
||||||
|
.min_luminance = 0.010f,
|
||||||
|
.max_luminance = 100.f,
|
||||||
|
.reference_white_luminance = 100.f,
|
||||||
|
.target_min_luminance = 0.010f,
|
||||||
|
.target_max_luminance = 100.f,
|
||||||
|
.maxCLL = NO_VALUE,
|
||||||
|
.maxFALL = NO_VALUE,
|
||||||
|
},
|
||||||
|
.tf = WESTON_TF_BT1886,
|
||||||
|
.named_prim = WESTON_PRIMARIES_CICP_BT2020,
|
||||||
|
.use_named_prim = true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
WESTON_EOTF_MODE_ST2084, WESTON_COLORIMETRY_MODE_BT2020_RGB,
|
||||||
|
"auto:",
|
||||||
|
"",
|
||||||
|
{
|
||||||
|
.template = {
|
||||||
|
.primaries = prim_bt2020,
|
||||||
|
.target_primaries = prim_bt2020,
|
||||||
|
.min_luminance = 0.005f,
|
||||||
|
.max_luminance = 10000.f,
|
||||||
|
.reference_white_luminance = 203.f,
|
||||||
|
.target_min_luminance = 0.005f,
|
||||||
|
.target_max_luminance = 10000.f,
|
||||||
|
.maxCLL = NO_VALUE,
|
||||||
|
.maxFALL = NO_VALUE,
|
||||||
|
},
|
||||||
|
.tf = WESTON_TF_ST2084_PQ,
|
||||||
|
.named_prim = WESTON_PRIMARIES_CICP_BT2020,
|
||||||
|
.use_named_prim = true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
WESTON_EOTF_MODE_HLG, WESTON_COLORIMETRY_MODE_BT2020_YCC,
|
||||||
|
"auto:",
|
||||||
|
"",
|
||||||
|
{
|
||||||
|
.template = {
|
||||||
|
.primaries = prim_bt2020,
|
||||||
|
.target_primaries = prim_bt2020,
|
||||||
|
.min_luminance = 0.005f,
|
||||||
|
.max_luminance = 1000.f,
|
||||||
|
.reference_white_luminance = 203.f,
|
||||||
|
.target_min_luminance = 0.005f,
|
||||||
|
.target_max_luminance = 1000.f,
|
||||||
|
.maxCLL = NO_VALUE,
|
||||||
|
.maxFALL = NO_VALUE,
|
||||||
|
},
|
||||||
|
.tf = WESTON_TF_HLG,
|
||||||
|
.named_prim = WESTON_PRIMARIES_CICP_BT2020,
|
||||||
|
.use_named_prim = true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
WESTON_EOTF_MODE_SDR, WESTON_COLORIMETRY_MODE_DEFAULT,
|
||||||
|
"auto:edid-primaries edid-tf edid-dr",
|
||||||
|
"",
|
||||||
|
{
|
||||||
|
.template = {
|
||||||
|
.primaries = prim_hp_5dq99aa,
|
||||||
|
.target_primaries = prim_hp_5dq99aa,
|
||||||
|
.tf.params = { 2.2f, },
|
||||||
|
.min_luminance = 0.2f,
|
||||||
|
.max_luminance = 80.f,
|
||||||
|
.reference_white_luminance = 80.f,
|
||||||
|
.target_min_luminance = 0.2f,
|
||||||
|
.target_max_luminance = 80.f,
|
||||||
|
.maxCLL = NO_VALUE,
|
||||||
|
.maxFALL = NO_VALUE,
|
||||||
|
},
|
||||||
|
.tf = WESTON_TF_POWER,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
WESTON_EOTF_MODE_ST2084, WESTON_COLORIMETRY_MODE_DEFAULT,
|
||||||
|
"auto:edid-primaries edid-tf edid-dr",
|
||||||
|
"",
|
||||||
|
{
|
||||||
|
.template = {
|
||||||
|
.primaries = prim_hp_5dq99aa,
|
||||||
|
.target_primaries = prim_hp_5dq99aa,
|
||||||
|
.min_luminance = 0.005f,
|
||||||
|
.max_luminance = 10000.f,
|
||||||
|
.reference_white_luminance = 203.f,
|
||||||
|
.target_min_luminance = 0.f,
|
||||||
|
.target_max_luminance = 603.6657f,
|
||||||
|
.maxCLL = NO_VALUE,
|
||||||
|
.maxFALL = 351.2504f,
|
||||||
|
},
|
||||||
|
.tf = WESTON_TF_ST2084_PQ,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
WESTON_EOTF_MODE_ST2084, WESTON_COLORIMETRY_MODE_BT2020_RGB,
|
||||||
|
"auto:edid-primaries edid-tf edid-dr",
|
||||||
|
"",
|
||||||
|
{
|
||||||
|
.template = {
|
||||||
|
.primaries = prim_bt2020,
|
||||||
|
.target_primaries = prim_bt2020,
|
||||||
|
.min_luminance = 0.005f,
|
||||||
|
.max_luminance = 10000.f,
|
||||||
|
.reference_white_luminance = 203.f,
|
||||||
|
.target_min_luminance = 0.f,
|
||||||
|
.target_max_luminance = 603.6657f,
|
||||||
|
.maxCLL = NO_VALUE,
|
||||||
|
.maxFALL = 351.2504f,
|
||||||
|
},
|
||||||
|
.tf = WESTON_TF_ST2084_PQ,
|
||||||
|
.named_prim = WESTON_PRIMARIES_CICP_BT2020,
|
||||||
|
.use_named_prim = true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
WESTON_EOTF_MODE_HLG, WESTON_COLORIMETRY_MODE_P3D65,
|
||||||
|
"srgb:",
|
||||||
|
"",
|
||||||
|
{
|
||||||
|
.template = {
|
||||||
|
.primaries = prim_bt709,
|
||||||
|
.target_primaries = prim_bt709,
|
||||||
|
.min_luminance = 0.2f,
|
||||||
|
.max_luminance = 80.f,
|
||||||
|
.reference_white_luminance = 80.f,
|
||||||
|
.target_min_luminance = 0.2f,
|
||||||
|
.target_max_luminance = 80.f,
|
||||||
|
.maxCLL = NO_VALUE,
|
||||||
|
.maxFALL = NO_VALUE,
|
||||||
|
},
|
||||||
|
.tf = WESTON_TF_GAMMA22,
|
||||||
|
.named_prim = WESTON_PRIMARIES_CICP_SRGB,
|
||||||
|
.use_named_prim = true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
WESTON_EOTF_MODE_SDR, WESTON_COLORIMETRY_MODE_DEFAULT,
|
||||||
|
"mydisp",
|
||||||
|
"prim_named=display_p3\n"
|
||||||
|
"target_named=srgb\n"
|
||||||
|
"tf_named=gamma22\n",
|
||||||
|
{
|
||||||
|
.template = {
|
||||||
|
.primaries = prim_display_p3,
|
||||||
|
.target_primaries = prim_bt709,
|
||||||
|
.min_luminance = 0.2f,
|
||||||
|
.max_luminance = 80.f,
|
||||||
|
.reference_white_luminance = 80.f,
|
||||||
|
.target_min_luminance = 0.2f,
|
||||||
|
.target_max_luminance = 80.f,
|
||||||
|
.maxCLL = NO_VALUE,
|
||||||
|
.maxFALL = NO_VALUE,
|
||||||
|
},
|
||||||
|
.tf = WESTON_TF_GAMMA22,
|
||||||
|
.named_prim = WESTON_PRIMARIES_CICP_DISPLAY_P3,
|
||||||
|
.use_named_prim = true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
WESTON_EOTF_MODE_SDR, WESTON_COLORIMETRY_MODE_DEFAULT,
|
||||||
|
"mydisp",
|
||||||
|
"prim_red=1.0 0\n"
|
||||||
|
"prim_green=0.0 1\n"
|
||||||
|
"prim_blue=0 0\n"
|
||||||
|
"prim_white=0.333333 0.333333\n"
|
||||||
|
"min_lum=0\n"
|
||||||
|
"ref_lum=150\n"
|
||||||
|
"max_lum=860\n"
|
||||||
|
"target_red=0.681 0.319\n"
|
||||||
|
"target_green=24.3e-2 6.92e-1\n"
|
||||||
|
"target_blue= 0.155\t0.07\n"
|
||||||
|
"target_white= \t 0.310 \t 0.316 \t\n"
|
||||||
|
"target_min_lum=1e-1\n"
|
||||||
|
"target_max_lum=555.5\n"
|
||||||
|
"max_fall=213\n"
|
||||||
|
"max_cll=550\n"
|
||||||
|
"tf_power=2.35\n",
|
||||||
|
{
|
||||||
|
.template = {
|
||||||
|
.primaries = {
|
||||||
|
.primary = {
|
||||||
|
{ 1.f, 0.f },
|
||||||
|
{ 0.f, 1.f },
|
||||||
|
{ 0.f, 0.f },
|
||||||
|
},
|
||||||
|
.white_point = { 1.f / 3, 1.f / 3 },
|
||||||
|
},
|
||||||
|
.target_primaries = {
|
||||||
|
.primary = {
|
||||||
|
{ 0.681f, 0.319f },
|
||||||
|
{ 0.243f, 0.692f },
|
||||||
|
{ 0.155f, 0.070f },
|
||||||
|
},
|
||||||
|
.white_point = { 0.310f, 0.316f },
|
||||||
|
},
|
||||||
|
.tf.params = { 2.35f, },
|
||||||
|
.min_luminance = 0.f,
|
||||||
|
.max_luminance = 860.f,
|
||||||
|
.reference_white_luminance = 150.f,
|
||||||
|
.target_min_luminance = 0.1f,
|
||||||
|
.target_max_luminance = 555.5f,
|
||||||
|
.maxCLL = 550.f,
|
||||||
|
.maxFALL = 213.f,
|
||||||
|
},
|
||||||
|
.tf = WESTON_TF_POWER,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct di_info *display_edid;
|
||||||
|
|
||||||
|
static int
|
||||||
|
logger(const char *fmt, va_list arg)
|
||||||
|
{
|
||||||
|
return vfprintf(stderr, fmt, arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum test_result_code
|
||||||
|
fixture_setup(struct weston_test_harness *harness)
|
||||||
|
{
|
||||||
|
enum test_result_code ret;
|
||||||
|
char *fname;
|
||||||
|
size_t len;
|
||||||
|
char *edid_data;
|
||||||
|
|
||||||
|
str_printf(&fname, "%s/hp-5dq99aa-hdmi.edid", reference_path());
|
||||||
|
abort_oom_if_null(fname);
|
||||||
|
|
||||||
|
len = read_blob_from_file(fname, &edid_data);
|
||||||
|
free(fname);
|
||||||
|
if (!test_assert_u64_gt(len, 0))
|
||||||
|
return RESULT_HARD_ERROR;
|
||||||
|
|
||||||
|
display_edid = di_info_parse_edid(edid_data, len);
|
||||||
|
free(edid_data);
|
||||||
|
abort_oom_if_null(display_edid);
|
||||||
|
|
||||||
|
ret = weston_test_harness_execute_standalone(harness);
|
||||||
|
|
||||||
|
di_info_destroy(display_edid);
|
||||||
|
display_edid = NULL;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
DECLARE_FIXTURE_SETUP(fixture_setup)
|
||||||
|
|
||||||
|
static struct weston_config *
|
||||||
|
create_config(const struct config_testcase *t)
|
||||||
|
{
|
||||||
|
struct compositor_setup setup;
|
||||||
|
struct weston_config *wc;
|
||||||
|
|
||||||
|
compositor_setup_defaults(&setup);
|
||||||
|
weston_ini_setup(&setup,
|
||||||
|
cfgln("[color-profile]"),
|
||||||
|
cfgln("name=mydisp"),
|
||||||
|
cfgln("%s", t->profile_string));
|
||||||
|
|
||||||
|
wc = weston_config_parse(setup.config_file);
|
||||||
|
test_assert_ptr_not_null(wc);
|
||||||
|
free(setup.config_file);
|
||||||
|
|
||||||
|
return wc;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct mock_color_manager {
|
||||||
|
struct weston_color_manager base;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mock_color_profile {
|
||||||
|
struct weston_color_profile base;
|
||||||
|
struct weston_color_profile_params params;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct mock_color_profile *
|
||||||
|
to_mock_cprof(struct weston_color_profile *cprof)
|
||||||
|
{
|
||||||
|
return container_of(cprof, struct mock_color_profile, base);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct weston_color_profile *
|
||||||
|
mock_cm_ref_stock_sRGB_color_profile(struct weston_color_manager *mock_cm)
|
||||||
|
{
|
||||||
|
struct mock_color_profile *mock_cprof;
|
||||||
|
|
||||||
|
mock_cprof = xzalloc(sizeof(*mock_cprof));
|
||||||
|
|
||||||
|
weston_color_profile_init(&mock_cprof->base, mock_cm);
|
||||||
|
str_printf(&mock_cprof->base.description, "Mock sRGB profile");
|
||||||
|
|
||||||
|
return &mock_cprof->base;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
mock_cm_get_color_profile_from_params(struct weston_color_manager *mock_cm,
|
||||||
|
const struct weston_color_profile_params *params,
|
||||||
|
const char *name_part,
|
||||||
|
struct weston_color_profile **cprof_out,
|
||||||
|
char **errmsg)
|
||||||
|
{
|
||||||
|
struct mock_color_profile *mock_cprof;
|
||||||
|
|
||||||
|
mock_cprof = xzalloc(sizeof(*mock_cprof));
|
||||||
|
|
||||||
|
weston_color_profile_init(&mock_cprof->base, mock_cm);
|
||||||
|
str_printf(&mock_cprof->base.description, "Mock profile %s", name_part);
|
||||||
|
mock_cprof->params = *params;
|
||||||
|
|
||||||
|
*cprof_out = &mock_cprof->base;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mock_cm_destroy_color_profile(struct weston_color_profile *cprof)
|
||||||
|
{
|
||||||
|
struct mock_color_profile *mock_cprof = to_mock_cprof(cprof);
|
||||||
|
|
||||||
|
free(mock_cprof->base.description);
|
||||||
|
free(mock_cprof);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
test_assert_CIExy_eq(const struct weston_CIExy *ref,
|
||||||
|
const struct weston_CIExy *tst,
|
||||||
|
float tolerance,
|
||||||
|
int indent,
|
||||||
|
const char *desc)
|
||||||
|
{
|
||||||
|
bool r = true;
|
||||||
|
|
||||||
|
r = test_assert_f32_absdiff_lt(ref->x, tst->x, tolerance) && r;
|
||||||
|
r = test_assert_f32_absdiff_lt(ref->y, tst->y, tolerance) && r;
|
||||||
|
|
||||||
|
if (!r)
|
||||||
|
testlog("%*sin %s\n", indent, "", desc);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
test_assert_color_gamut_eq(const struct weston_color_gamut *ref,
|
||||||
|
const struct weston_color_gamut *tst,
|
||||||
|
float tolerance,
|
||||||
|
int indent,
|
||||||
|
const char *desc)
|
||||||
|
{
|
||||||
|
static const char *chan[] = { "red", "green", "blue" };
|
||||||
|
bool r = true;
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_LENGTH(tst->primary); i++) {
|
||||||
|
r = test_assert_CIExy_eq(&ref->primary[i], &tst->primary[i],
|
||||||
|
tolerance, indent + 2, chan[i]) && r;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = test_assert_CIExy_eq(&ref->white_point, &tst->white_point,
|
||||||
|
tolerance, indent + 2, "white point") && r;
|
||||||
|
|
||||||
|
if (!r)
|
||||||
|
testlog("%*sin %s\n", indent, "", desc);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
assert_params_equal(const struct weston_color_profile_params *ref,
|
||||||
|
const struct weston_color_profile_params *tst)
|
||||||
|
{
|
||||||
|
float tol = 0.0001;
|
||||||
|
int indent = 4;
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
test_assert_color_gamut_eq(&tst->primaries, &ref->primaries, tol, indent, "primaries");
|
||||||
|
test_assert_ptr_eq(tst->primaries_info, ref->primaries_info);
|
||||||
|
|
||||||
|
test_assert_ptr_eq(tst->tf.info, ref->tf.info);
|
||||||
|
for (i = 0; i < ARRAY_LENGTH(tst->tf.params); i++) {
|
||||||
|
if (!test_assert_f32_absdiff_lt(ref->tf.params[i], tst->tf.params[i], tol))
|
||||||
|
testlog("%*sin tf.params[%d]\n", indent, "", i);
|
||||||
|
}
|
||||||
|
|
||||||
|
test_assert_f32_absdiff_lt(ref->min_luminance, tst->min_luminance, tol);
|
||||||
|
test_assert_f32_absdiff_lt(ref->max_luminance, tst->max_luminance, tol);
|
||||||
|
test_assert_f32_absdiff_lt(ref->reference_white_luminance, tst->reference_white_luminance, tol);
|
||||||
|
|
||||||
|
test_assert_color_gamut_eq(&ref->target_primaries, &tst->target_primaries,
|
||||||
|
tol, indent, "target primaries");
|
||||||
|
|
||||||
|
test_assert_f32_absdiff_lt(ref->target_min_luminance, tst->target_min_luminance, tol);
|
||||||
|
test_assert_f32_absdiff_lt(ref->target_max_luminance, tst->target_max_luminance, tol);
|
||||||
|
test_assert_f32_absdiff_lt(ref->maxCLL, tst->maxCLL, tol);
|
||||||
|
test_assert_f32_absdiff_lt(ref->maxFALL, tst->maxFALL, tol);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
compare_results(struct weston_color_profile *tst,
|
||||||
|
const struct expected_params *expected)
|
||||||
|
{
|
||||||
|
const struct mock_color_profile *mock_cprof = to_mock_cprof(tst);
|
||||||
|
struct weston_color_profile_params ref = expected->template;
|
||||||
|
|
||||||
|
ref.tf.info = weston_color_tf_info_from(NULL, expected->tf);
|
||||||
|
|
||||||
|
if (expected->use_named_prim) {
|
||||||
|
ref.primaries_info = weston_color_primaries_info_from(NULL, expected->named_prim);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_params_equal(&ref, &mock_cprof->params);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Manufacture various weston.ini and check what
|
||||||
|
* wet_create_output_color_profile() says. Tests for the return value and
|
||||||
|
* the error messages logged.
|
||||||
|
*/
|
||||||
|
TEST_P(parametric_color_profile_parsing, config_cases)
|
||||||
|
{
|
||||||
|
const struct config_testcase *t = data;
|
||||||
|
struct weston_color_profile *cprof;
|
||||||
|
struct weston_config *wc;
|
||||||
|
struct mock_color_manager mock_cm = {
|
||||||
|
.base.ref_stock_sRGB_color_profile = mock_cm_ref_stock_sRGB_color_profile,
|
||||||
|
.base.get_color_profile_from_params = mock_cm_get_color_profile_from_params,
|
||||||
|
.base.destroy_color_profile = mock_cm_destroy_color_profile,
|
||||||
|
.base.supported_color_features = 0xffffffff,
|
||||||
|
.base.supported_primaries_named = 0xffffffff,
|
||||||
|
.base.supported_tf_named = 0xffffffff,
|
||||||
|
};
|
||||||
|
struct weston_compositor mock_compositor = {
|
||||||
|
.color_manager = &mock_cm.base,
|
||||||
|
.color_profile_id_generator = weston_idalloc_create(&mock_compositor),
|
||||||
|
};
|
||||||
|
struct weston_output mock_output = {};
|
||||||
|
struct weston_head mock_head = {};
|
||||||
|
|
||||||
|
mock_cm.base.compositor = &mock_compositor;
|
||||||
|
|
||||||
|
wl_list_init(&mock_compositor.plane_list);
|
||||||
|
|
||||||
|
weston_log_set_handler(logger, logger);
|
||||||
|
|
||||||
|
weston_head_init(&mock_head, "mock head");
|
||||||
|
weston_head_set_supported_eotf_mask(&mock_head, WESTON_EOTF_MODE_ALL_MASK);
|
||||||
|
weston_head_set_supported_colorimetry_mask(&mock_head, WESTON_COLORIMETRY_MODE_ALL_MASK);
|
||||||
|
mock_head.display_info = display_edid; /* from fixture_setup() */
|
||||||
|
|
||||||
|
weston_output_init(&mock_output, &mock_compositor, "mockoutput");
|
||||||
|
weston_output_attach_head(&mock_output, &mock_head);
|
||||||
|
weston_output_set_eotf_mode(&mock_output, t->eotf_mode);
|
||||||
|
weston_output_set_colorimetry_mode(&mock_output, t->colorimetry_mode);
|
||||||
|
|
||||||
|
wc = create_config(t);
|
||||||
|
cprof = wet_create_output_color_profile(&mock_output, wc, t->profile_name);
|
||||||
|
test_assert_ptr_not_null(cprof);
|
||||||
|
|
||||||
|
compare_results(cprof, &t->expected);
|
||||||
|
|
||||||
|
weston_color_profile_unref(cprof);
|
||||||
|
|
||||||
|
weston_config_destroy(wc);
|
||||||
|
weston_output_release(&mock_output);
|
||||||
|
mock_head.display_info = NULL; /* freed in fixture_setup() */
|
||||||
|
weston_head_release(&mock_head);
|
||||||
|
weston_idalloc_destroy(mock_compositor.color_profile_id_generator);
|
||||||
|
|
||||||
|
return RESULT_OK;
|
||||||
|
}
|
||||||
|
|
@ -125,6 +125,13 @@ tests = [
|
||||||
'name': 'color-metadata-errors',
|
'name': 'color-metadata-errors',
|
||||||
'dep_objs': dep_libexec_weston,
|
'dep_objs': dep_libexec_weston,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
'name': 'color-output-parsing',
|
||||||
|
'dep_objs': [
|
||||||
|
dep_libexec_weston,
|
||||||
|
dep_libdisplay_info,
|
||||||
|
],
|
||||||
|
},
|
||||||
{ 'name': 'config-parser', },
|
{ 'name': 'config-parser', },
|
||||||
{
|
{
|
||||||
'name': 'constraints',
|
'name': 'constraints',
|
||||||
|
|
|
||||||
BIN
tests/reference/hp-5dq99aa-hdmi.edid
Normal file
BIN
tests/reference/hp-5dq99aa-hdmi.edid
Normal file
Binary file not shown.
5
tests/reference/hp-5dq99aa-hdmi.edid.license
Normal file
5
tests/reference/hp-5dq99aa-hdmi.edid.license
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
not copyrightable, no license
|
||||||
|
|
||||||
|
Pekka Paalanen captured this EDID from a HP Pavilion 27 Quantum Dot
|
||||||
|
display in 2022.
|
||||||
|
|
||||||
|
|
@ -157,6 +157,19 @@ test_assert_fail(void *compositor, const char *fmt, ...)
|
||||||
#define test_assert_f32_lt(a, b) weston_assert_(NULL, a, b, float, "%.10g", <)
|
#define test_assert_f32_lt(a, b) weston_assert_(NULL, a, b, float, "%.10g", <)
|
||||||
#define test_assert_f32_le(a, b) weston_assert_(NULL, a, b, float, "%.10g", <=)
|
#define test_assert_f32_le(a, b) weston_assert_(NULL, a, b, float, "%.10g", <=)
|
||||||
|
|
||||||
|
#define test_assert_f32_absdiff_lt(a, b, tol) \
|
||||||
|
({ \
|
||||||
|
float a_ = (a); \
|
||||||
|
float b_ = (b); \
|
||||||
|
float tol_ = (tol); \
|
||||||
|
float absdiff = fabsf(a_ - b_); \
|
||||||
|
bool cond = absdiff < tol_; \
|
||||||
|
if (!cond) \
|
||||||
|
custom_assert_fail_(NULL, "%s:%u: Assertion %s ≈≈ %s (|%.10g - %.10g| < %.10g) failed!\n", \
|
||||||
|
__FILE__, __LINE__, #a, #b, a_, b_, tol_); \
|
||||||
|
cond; \
|
||||||
|
})
|
||||||
|
|
||||||
#define test_assert_f64_eq(a, b) weston_assert_(NULL, a, b, double, "%.10g", ==)
|
#define test_assert_f64_eq(a, b) weston_assert_(NULL, a, b, double, "%.10g", ==)
|
||||||
#define test_assert_f64_ne(a, b) weston_assert_(NULL, a, b, double, "%.10g", !=)
|
#define test_assert_f64_ne(a, b) weston_assert_(NULL, a, b, double, "%.10g", !=)
|
||||||
#define test_assert_f64_gt(a, b) weston_assert_(NULL, a, b, double, "%.10g", >)
|
#define test_assert_f64_gt(a, b) weston_assert_(NULL, a, b, double, "%.10g", >)
|
||||||
|
|
@ -164,6 +177,19 @@ test_assert_fail(void *compositor, const char *fmt, ...)
|
||||||
#define test_assert_f64_lt(a, b) weston_assert_(NULL, a, b, double, "%.10g", <)
|
#define test_assert_f64_lt(a, b) weston_assert_(NULL, a, b, double, "%.10g", <)
|
||||||
#define test_assert_f64_le(a, b) weston_assert_(NULL, a, b, double, "%.10g", <=)
|
#define test_assert_f64_le(a, b) weston_assert_(NULL, a, b, double, "%.10g", <=)
|
||||||
|
|
||||||
|
#define test_assert_f64_absdiff_lt(a, b, tol) \
|
||||||
|
({ \
|
||||||
|
double a_ = (a); \
|
||||||
|
double b_ = (b); \
|
||||||
|
double tol_ = (tol); \
|
||||||
|
double absdiff = fabs(a_ - b_); \
|
||||||
|
bool cond = absdiff < tol_; \
|
||||||
|
if (!cond) \
|
||||||
|
custom_assert_fail_(NULL, "%s:%u: Assertion %s ≈≈ %s (|%.10g - %.10g| < %.10g) failed!\n", \
|
||||||
|
__FILE__, __LINE__, #a, #b, a_, b_, tol_); \
|
||||||
|
cond; \
|
||||||
|
})
|
||||||
|
|
||||||
/* Various helpers. */
|
/* Various helpers. */
|
||||||
|
|
||||||
#define test_assert_bit_set(a, bit) weston_assert_bit_set(NULL, a, bit)
|
#define test_assert_bit_set(a, bit) weston_assert_bit_set(NULL, a, bit)
|
||||||
|
|
|
||||||
|
|
@ -1251,7 +1251,7 @@ output_path(void)
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char*
|
const char *
|
||||||
reference_path(void)
|
reference_path(void)
|
||||||
{
|
{
|
||||||
char *path = getenv("WESTON_TEST_REFERENCE_PATH");
|
char *path = getenv("WESTON_TEST_REFERENCE_PATH");
|
||||||
|
|
@ -1407,6 +1407,58 @@ fopen_dump_file(const char *suffix)
|
||||||
return fp;
|
return fp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read a file into a newly malloc'd memory.
|
||||||
|
*
|
||||||
|
* \param fname Full name of the file to read.
|
||||||
|
* \param data_out Pointer where to store the pointer to the read data.
|
||||||
|
* \return Length of the data, or 0 on error.
|
||||||
|
*
|
||||||
|
* On error, *data_out is not modified. On success, *data_out contains a
|
||||||
|
* pointer to the data and must be free()'d by the caller.
|
||||||
|
*/
|
||||||
|
size_t
|
||||||
|
read_blob_from_file(const char *fname, char **data_out)
|
||||||
|
{
|
||||||
|
struct wl_array data;
|
||||||
|
char tmpbuf[64];
|
||||||
|
FILE *fp;
|
||||||
|
size_t len;
|
||||||
|
void *p;
|
||||||
|
int fer;
|
||||||
|
|
||||||
|
testlog("%s: %s\n", __func__, fname);
|
||||||
|
|
||||||
|
wl_array_init(&data);
|
||||||
|
|
||||||
|
fp = fopen(fname, "rb");
|
||||||
|
if (!test_assert_ptr_not_null(fp)) {
|
||||||
|
wl_array_release(&data);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!feof(fp)) {
|
||||||
|
len = fread(tmpbuf, 1, sizeof tmpbuf, fp);
|
||||||
|
if (len == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
p = wl_array_add(&data, len);
|
||||||
|
abort_oom_if_null(p);
|
||||||
|
memcpy(p, tmpbuf, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
fer = ferror(fp);
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
if (fer) {
|
||||||
|
wl_array_release(&data);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
*data_out = data.data;
|
||||||
|
return data.size;
|
||||||
|
}
|
||||||
|
|
||||||
struct format_map_entry {
|
struct format_map_entry {
|
||||||
cairo_format_t cairo;
|
cairo_format_t cairo;
|
||||||
pixman_format_code_t pixman;
|
pixman_format_code_t pixman;
|
||||||
|
|
|
||||||
|
|
@ -267,6 +267,9 @@ void
|
||||||
expect_protocol_error(struct client *client,
|
expect_protocol_error(struct client *client,
|
||||||
const struct wl_interface *intf, uint32_t code);
|
const struct wl_interface *intf, uint32_t code);
|
||||||
|
|
||||||
|
const char *
|
||||||
|
reference_path(void);
|
||||||
|
|
||||||
char *
|
char *
|
||||||
screenshot_reference_filename(const char *basename, uint32_t seq);
|
screenshot_reference_filename(const char *basename, uint32_t seq);
|
||||||
|
|
||||||
|
|
@ -289,6 +292,9 @@ output_filename_for_test_case(const char *suffix, uint32_t seq_number,
|
||||||
FILE *
|
FILE *
|
||||||
fopen_dump_file(const char *suffix);
|
fopen_dump_file(const char *suffix);
|
||||||
|
|
||||||
|
size_t
|
||||||
|
read_blob_from_file(const char *fname, char **data_out);
|
||||||
|
|
||||||
bool
|
bool
|
||||||
check_images_match(pixman_image_t *img_a, pixman_image_t *img_b,
|
check_images_match(pixman_image_t *img_a, pixman_image_t *img_b,
|
||||||
const struct rectangle *clip,
|
const struct rectangle *clip,
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue