@ -33,12 +33,6 @@
# include "color-lcms.h"
# include "shared/helpers.h"
/* Arguments to cmsBuildParametricToneCurve() */
struct tone_curve_def {
cmsInt32Number cmstype ;
cmsFloat64Number params [ 5 ] ;
} ;
/**
* The method is used in linearization of an arbitrary color profile
* when EOTF is retrieved we want to know a generic way to decide the number
@ -50,42 +44,87 @@ cmlcms_reasonable_1D_points(void)
return 1024 ;
}
/*
* LCMS uses the required number of ' params ' based on ' cmstype ' , the parametric
* tone curve number . LCMS honors negative ' cmstype ' as inverse function .
* These are LCMS built - in parametric tone curves .
*/
static const struct tone_curve_def predefined_eotf_curves [ ] = {
[ CMLCMS_TYPE_EOTF_sRGB ] = {
. cmstype = 4 ,
. params = { 2.4 , 1. / 1.055 , 0.055 / 1.055 , 1. / 12.92 , 0.04045 } ,
} ,
[ CMLCMS_TYPE_EOTF_sRGB_INV ] = {
. cmstype = - 4 ,
. params = { 2.4 , 1. / 1.055 , 0.055 / 1.055 , 1. / 12.92 , 0.04045 } ,
} ,
} ;
static unsigned int
cmlcms_reasonable_3D_points ( void )
{
return 33 ;
}
static void
cmlcms_fill_in_tone_curve ( struct weston_color_transform * xform_base ,
float * values , unsigned len )
fill_in_curves ( cmsToneCurve * curves [ 3 ] , float * values , unsigned len )
{
struct cmlcms_color_transform * xform = get_xform ( xform_base ) ;
float * R_lut = values ;
float * G_lut = R_lut + len ;
float * B_lut = G_lut + len ;
unsigned i ;
cmsFloat32Number x , y ;
assert ( xform - > curve ! = NULL ) ;
assert ( len > 1 ) ;
cmsFloat32Number x ;
for ( i = 0 ; i < len ; i + + ) {
x = ( double ) i / ( len - 1 ) ;
y = cmsEvalToneCurveFloat ( xform - > curve , x ) ;
R_lut [ i ] = y ;
G_lut [ i ] = y ;
B_lut [ i ] = y ;
R_lut [ i ] = cmsEvalToneCurveFloat ( curves [ 0 ] , x ) ;
G_lut [ i ] = cmsEvalToneCurveFloat ( curves [ 1 ] , x ) ;
B_lut [ i ] = cmsEvalToneCurveFloat ( curves [ 2 ] , x ) ;
}
}
static void
cmlcms_fill_in_pre_curve ( struct weston_color_transform * xform_base ,
float * values , unsigned len )
{
struct cmlcms_color_transform * xform = get_xform ( xform_base ) ;
assert ( xform - > search_key . category = = CMLCMS_CATEGORY_BLEND_TO_OUTPUT ) ;
assert ( len > 1 ) ;
fill_in_curves ( xform - > search_key . output_profile - > output_inv_eotf_vcgt ,
values , len ) ;
}
/**
* Clamp value to [ 0.0 , 1.0 ] , except pass NaN through .
*
* This function is not intended for hiding NaN .
*/
static float
ensure_unorm ( float v )
{
if ( v < = 0.0f )
return 0.0f ;
if ( v > 1.0f )
return 1.0f ;
return v ;
}
static void
cmlcms_fill_in_3dlut ( struct weston_color_transform * xform_base ,
float * lut , unsigned int len )
{
struct cmlcms_color_transform * xform = get_xform ( xform_base ) ;
float rgb_in [ 3 ] ;
float rgb_out [ 3 ] ;
unsigned int index ;
unsigned int value_b , value_r , value_g ;
float divider = len - 1 ;
assert ( xform - > search_key . category = = CMLCMS_CATEGORY_INPUT_TO_BLEND | |
xform - > search_key . category = = CMLCMS_CATEGORY_INPUT_TO_OUTPUT ) ;
for ( value_b = 0 ; value_b < len ; value_b + + ) {
for ( value_g = 0 ; value_g < len ; value_g + + ) {
for ( value_r = 0 ; value_r < len ; value_r + + ) {
rgb_in [ 0 ] = ( float ) value_r / divider ;
rgb_in [ 1 ] = ( float ) value_g / divider ;
rgb_in [ 2 ] = ( float ) value_b / divider ;
cmsDoTransform ( xform - > cmap_3dlut , rgb_in , rgb_out , 1 ) ;
index = 3 * ( value_r + len * ( value_g + len * value_b ) ) ;
lut [ index ] = ensure_unorm ( rgb_out [ 0 ] ) ;
lut [ index + 1 ] = ensure_unorm ( rgb_out [ 1 ] ) ;
lut [ index + 2 ] = ensure_unorm ( rgb_out [ 2 ] ) ;
}
}
}
}
@ -93,57 +132,129 @@ void
cmlcms_color_transform_destroy ( struct cmlcms_color_transform * xform )
{
wl_list_remove ( & xform - > link ) ;
if ( xform - > curve )
cmsFreeToneCurve ( xform - > curve ) ;
if ( xform - > cmap_3dlut )
cmsDeleteTransform ( xform - > cmap_3dlut ) ;
unref_cprof ( xform - > search_key . input_profile ) ;
unref_cprof ( xform - > search_key . output_profile ) ;
free ( xform ) ;
}
static bool
xform_set_cmap_3dlut ( struct cmlcms_color_transform * xform ,
cmsHPROFILE input_profile ,
cmsHPROFILE output_profile ,
cmsToneCurve * curves [ 3 ] ,
cmsUInt32Number intent )
{
struct weston_color_manager_lcms * cm = get_cmlcms ( xform - > base . cm ) ;
cmsHPROFILE arr_prof [ 3 ] = { input_profile , output_profile , NULL } ;
int num_profiles = 2 ;
if ( curves [ 0 ] ) {
arr_prof [ 2 ] = cmsCreateLinearizationDeviceLinkTHR ( cm - > lcms_ctx ,
cmsSigRgbData ,
curves ) ;
if ( ! arr_prof [ 2 ] )
return false ;
num_profiles = 3 ;
}
xform - > cmap_3dlut = cmsCreateMultiprofileTransformTHR ( cm - > lcms_ctx ,
arr_prof ,
num_profiles ,
TYPE_RGB_FLT ,
TYPE_RGB_FLT ,
intent ,
0 ) ;
if ( ! xform - > cmap_3dlut ) {
cmsCloseProfile ( arr_prof [ 2 ] ) ;
weston_log ( " color-lcms error: fail cmsCreateMultiprofileTransformTHR. \n " ) ;
return false ;
}
xform - > base . mapping . type = WESTON_COLOR_MAPPING_TYPE_3D_LUT ;
xform - > base . mapping . u . lut3d . fill_in = cmlcms_fill_in_3dlut ;
xform - > base . mapping . u . lut3d . optimal_len =
cmlcms_reasonable_3D_points ( ) ;
cmsCloseProfile ( arr_prof [ 2 ] ) ;
return true ;
}
static struct cmlcms_color_transform *
cmlcms_color_transform_create ( struct weston_color_manager_lcms * cm ,
const struct cmlcms_color_transform_search_param * param )
const struct cmlcms_color_transform_search_param * search_ param)
{
struct cmlcms_color_profile * input_profile = search_param - > input_profile ;
struct cmlcms_color_profile * output_profile = search_param - > output_profile ;
struct cmlcms_color_transform * xform ;
const struct tone_curve_def * tonedef ;
if ( param - > type < 0 | | param - > type > = CMLCMS_TYPE__END ) {
weston_log ( " color-lcms error: bad color transform type in %s. \n " ,
__func__ ) ;
return NULL ;
}
tonedef = & predefined_eotf_curves [ param - > type ] ;
bool ok = false ;
xform = zalloc ( sizeof * xform ) ;
if ( ! xform )
return NULL ;
xform - > curve = cmsBuildParametricToneCurve ( cm - > lcms_ctx ,
tonedef - > cmstype ,
tonedef - > params ) ;
if ( xform - > curve = = NULL ) {
weston_log ( " color-lcms error: failed to build parametric tone curve. \n " ) ;
free ( xform ) ;
return NULL ;
weston_color_transform_init ( & xform - > base , & cm - > base ) ;
wl_list_init ( & xform - > link ) ;
xform - > search_key = * search_param ;
xform - > search_key . input_profile = ref_cprof ( input_profile ) ;
xform - > search_key . output_profile = ref_cprof ( output_profile ) ;
/* Ensure the linearization etc. have been extracted. */
if ( ! output_profile - > output_eotf [ 0 ] ) {
if ( ! retrieve_eotf_and_output_inv_eotf ( cm - > lcms_ctx ,
output_profile - > profile ,
output_profile - > output_eotf ,
output_profile - > output_inv_eotf_vcgt ,
output_profile - > vcgt ,
cmlcms_reasonable_1D_points ( ) ) )
goto error ;
}
weston_color_transform_init ( & xform - > base , & cm - > base ) ;
xform - > search_key = * param ;
switch ( search_param - > category ) {
case CMLCMS_CATEGORY_INPUT_TO_BLEND :
/* Use EOTF to linearize the result. */
ok = xform_set_cmap_3dlut ( xform , input_profile - > profile ,
output_profile - > profile ,
output_profile - > output_eotf ,
search_param - > intent_output ) ;
break ;
case CMLCMS_CATEGORY_INPUT_TO_OUTPUT :
/* Apply also VCGT if it exists. */
ok = xform_set_cmap_3dlut ( xform , input_profile - > profile ,
output_profile - > profile ,
output_profile - > vcgt ,
search_param - > intent_output ) ;
break ;
case CMLCMS_CATEGORY_BLEND_TO_OUTPUT :
xform - > base . pre_curve . type = WESTON_COLOR_CURVE_TYPE_LUT_3x1D ;
xform - > base . pre_curve . u . lut_3x1d . fill_in = cmlcms_fill_in_tone_curve ;
xform - > base . pre_curve . u . lut_3x1d . optimal_len = 256 ;
xform - > base . pre_curve . u . lut_3x1d . fill_in = cmlcms_fill_in_pre_curve ;
xform - > base . pre_curve . u . lut_3x1d . optimal_len =
cmlcms_reasonable_1D_points ( ) ;
ok = true ;
break ;
}
wl_list_insert ( & cm - > color_transform_list , & xform - > link ) ;
if ( ! ok )
goto error ;
wl_list_insert ( & cm - > color_transform_list , & xform - > link ) ;
return xform ;
error :
cmlcms_color_transform_destroy ( xform ) ;
weston_log ( " CM cmlcms_color_transform_create failed \n " ) ;
return NULL ;
}
static bool
transform_matches_params ( const struct cmlcms_color_transform * xform ,
const struct cmlcms_color_transform_search_param * param )
{
if ( xform - > search_key . type ! = param - > type )
return false ;
if ( xform - > search_key . category ! = param - > category )
return false ;