mirror of
https://gitlab.freedesktop.org/wlroots/wlroots.git
synced 2025-10-29 05:40:12 -04:00
render/color: add wlr_color_transform_eval()
Makes it so the Vulkan renderer can handle arbitrary color transforms, and doesn't need to be updated each time a new one is added.
This commit is contained in:
parent
d786e07899
commit
3d36ab9211
4 changed files with 82 additions and 25 deletions
|
|
@ -72,12 +72,6 @@ struct wlr_color_transform_inverse_eotf *wlr_color_transform_inverse_eotf_from_b
|
||||||
struct wlr_color_transform_lut_3x1d *color_transform_lut_3x1d_from_base(
|
struct wlr_color_transform_lut_3x1d *color_transform_lut_3x1d_from_base(
|
||||||
struct wlr_color_transform *tr);
|
struct wlr_color_transform *tr);
|
||||||
|
|
||||||
/**
|
|
||||||
* Evaluate a 3x1D LUT color transform for a given RGB triplet.
|
|
||||||
*/
|
|
||||||
void color_transform_lut_3x1d_eval(struct wlr_color_transform_lut_3x1d *tr,
|
|
||||||
float out[static 3], const float in[static 3]);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Obtain primaries values from a well-known primaries name.
|
* Obtain primaries values from a well-known primaries name.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -152,4 +152,10 @@ struct wlr_color_transform *wlr_color_transform_ref(struct wlr_color_transform *
|
||||||
*/
|
*/
|
||||||
void wlr_color_transform_unref(struct wlr_color_transform *tr);
|
void wlr_color_transform_unref(struct wlr_color_transform *tr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Evaluate a color transform for a given RGB triplet.
|
||||||
|
*/
|
||||||
|
void wlr_color_transform_eval(struct wlr_color_transform *tr,
|
||||||
|
float out[static 3], const float in[static 3]);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -108,6 +108,65 @@ struct wlr_color_transform_lut_3x1d *color_transform_lut_3x1d_from_base(
|
||||||
return lut_3x1d;
|
return lut_3x1d;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static float srgb_eval_inverse_eotf(float x) {
|
||||||
|
// See https://www.w3.org/Graphics/Color/srgb
|
||||||
|
if (x <= 0.0031308) {
|
||||||
|
return 12.92 * x;
|
||||||
|
} else {
|
||||||
|
return 1.055 * powf(x, 1.0 / 2.4) - 0.055;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static float st2084_pq_eval_inverse_eotf(float x) {
|
||||||
|
// H.273 TransferCharacteristics code point 16
|
||||||
|
float c1 = 0.8359375;
|
||||||
|
float c2 = 18.8515625;
|
||||||
|
float c3 = 18.6875;
|
||||||
|
float m = 78.84375;
|
||||||
|
float n = 0.1593017578125;
|
||||||
|
if (x < 0) {
|
||||||
|
x = 0;
|
||||||
|
}
|
||||||
|
if (x > 1) {
|
||||||
|
x = 1;
|
||||||
|
}
|
||||||
|
float pow_n = powf(x, n);
|
||||||
|
return powf((c1 + c2 * pow_n) / (1 + c3 * pow_n), m);
|
||||||
|
}
|
||||||
|
|
||||||
|
static float bt1886_eval_inverse_eotf(float x) {
|
||||||
|
float lb = powf(0.0001, 1.0 / 2.4);
|
||||||
|
float lw = powf(1.0, 1.0 / 2.4);
|
||||||
|
float a = powf(lw - lb, 2.4);
|
||||||
|
float b = lb / (lw - lb);
|
||||||
|
return powf(x / a, 1.0 / 2.4) - b;
|
||||||
|
}
|
||||||
|
|
||||||
|
static float transfer_function_eval_inverse_eotf(
|
||||||
|
enum wlr_color_transfer_function tf, float x) {
|
||||||
|
switch (tf) {
|
||||||
|
case WLR_COLOR_TRANSFER_FUNCTION_SRGB:
|
||||||
|
return srgb_eval_inverse_eotf(x);
|
||||||
|
case WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ:
|
||||||
|
return st2084_pq_eval_inverse_eotf(x);
|
||||||
|
case WLR_COLOR_TRANSFER_FUNCTION_EXT_LINEAR:
|
||||||
|
return x;
|
||||||
|
case WLR_COLOR_TRANSFER_FUNCTION_GAMMA22:
|
||||||
|
return powf(x, 1.0 / 2.2);
|
||||||
|
case WLR_COLOR_TRANSFER_FUNCTION_BT1886:
|
||||||
|
return bt1886_eval_inverse_eotf(x);
|
||||||
|
}
|
||||||
|
abort(); // unreachable
|
||||||
|
}
|
||||||
|
|
||||||
|
static void color_transform_inverse_eotf_eval(
|
||||||
|
struct wlr_color_transform_inverse_eotf *tr,
|
||||||
|
float out[static 3], const float in[static 3]) {
|
||||||
|
for (size_t i = 0; i < 3; i++) {
|
||||||
|
out[i] = transfer_function_eval_inverse_eotf(tr->tf, in[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static float lut_1d_get(const uint16_t *lut, size_t len, size_t i) {
|
static float lut_1d_get(const uint16_t *lut, size_t len, size_t i) {
|
||||||
if (i >= len) {
|
if (i >= len) {
|
||||||
i = len - 1;
|
i = len - 1;
|
||||||
|
|
@ -125,13 +184,28 @@ static float lut_1d_eval(const uint16_t *lut, size_t len, float x) {
|
||||||
return a * (1 - frac_part) + b * frac_part;
|
return a * (1 - frac_part) + b * frac_part;
|
||||||
}
|
}
|
||||||
|
|
||||||
void color_transform_lut_3x1d_eval(struct wlr_color_transform_lut_3x1d *tr,
|
static void color_transform_lut_3x1d_eval(struct wlr_color_transform_lut_3x1d *tr,
|
||||||
float out[static 3], const float in[static 3]) {
|
float out[static 3], const float in[static 3]) {
|
||||||
for (size_t i = 0; i < 3; i++) {
|
for (size_t i = 0; i < 3; i++) {
|
||||||
out[i] = lut_1d_eval(&tr->lut_3x1d[tr->dim * i], tr->dim, in[i]);
|
out[i] = lut_1d_eval(&tr->lut_3x1d[tr->dim * i], tr->dim, in[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void wlr_color_transform_eval(struct wlr_color_transform *tr,
|
||||||
|
float out[static 3], const float in[static 3]) {
|
||||||
|
switch (tr->type) {
|
||||||
|
case COLOR_TRANSFORM_INVERSE_EOTF:
|
||||||
|
color_transform_inverse_eotf_eval(wlr_color_transform_inverse_eotf_from_base(tr), out, in);
|
||||||
|
break;
|
||||||
|
case COLOR_TRANSFORM_LCMS2:
|
||||||
|
color_transform_lcms2_eval(color_transform_lcms2_from_base(tr), out, in);
|
||||||
|
break;
|
||||||
|
case COLOR_TRANSFORM_LUT_3X1D:
|
||||||
|
color_transform_lut_3x1d_eval(color_transform_lut_3x1d_from_base(tr), out, in);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void wlr_color_primaries_from_named(struct wlr_color_primaries *out,
|
void wlr_color_primaries_from_named(struct wlr_color_primaries *out,
|
||||||
enum wlr_color_named_primaries named) {
|
enum wlr_color_named_primaries named) {
|
||||||
switch (named) {
|
switch (named) {
|
||||||
|
|
|
||||||
|
|
@ -964,19 +964,6 @@ static bool create_3d_lut_image(struct wlr_vk_renderer *renderer,
|
||||||
*ds = VK_NULL_HANDLE;
|
*ds = VK_NULL_HANDLE;
|
||||||
*ds_pool = NULL;
|
*ds_pool = NULL;
|
||||||
|
|
||||||
struct wlr_color_transform_lcms2 *tr_lcms2 = NULL;
|
|
||||||
struct wlr_color_transform_lut_3x1d *tr_lut_3x1d = NULL;
|
|
||||||
switch (tr->type) {
|
|
||||||
case COLOR_TRANSFORM_INVERSE_EOTF:
|
|
||||||
abort(); // unreachable
|
|
||||||
case COLOR_TRANSFORM_LCMS2:
|
|
||||||
tr_lcms2 = color_transform_lcms2_from_base(tr);
|
|
||||||
break;
|
|
||||||
case COLOR_TRANSFORM_LUT_3X1D:
|
|
||||||
tr_lut_3x1d = color_transform_lut_3x1d_from_base(tr);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// R32G32B32 is not a required Vulkan format
|
// R32G32B32 is not a required Vulkan format
|
||||||
// TODO: use it when available
|
// TODO: use it when available
|
||||||
VkFormat format = VK_FORMAT_R32G32B32A32_SFLOAT;
|
VkFormat format = VK_FORMAT_R32G32B32A32_SFLOAT;
|
||||||
|
|
@ -1074,11 +1061,7 @@ static bool create_3d_lut_image(struct wlr_vk_renderer *renderer,
|
||||||
b_index * sample_range,
|
b_index * sample_range,
|
||||||
};
|
};
|
||||||
float rgb_out[3];
|
float rgb_out[3];
|
||||||
if (tr_lcms2 != NULL) {
|
wlr_color_transform_eval(tr, rgb_out, rgb_in);
|
||||||
color_transform_lcms2_eval(tr_lcms2, rgb_out, rgb_in);
|
|
||||||
} else {
|
|
||||||
color_transform_lut_3x1d_eval(tr_lut_3x1d, rgb_out, rgb_in);
|
|
||||||
}
|
|
||||||
|
|
||||||
dst[dst_offset] = rgb_out[0];
|
dst[dst_offset] = rgb_out[0];
|
||||||
dst[dst_offset + 1] = rgb_out[1];
|
dst[dst_offset + 1] = rgb_out[1];
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue