drm/amd/display: Framework for degamma and regramma through color module
authorAmy Zhang <Amy.Zhang@amd.com>
Mon, 12 Dec 2016 21:57:40 +0000 (16:57 -0500)
committerAlex Deucher <alexander.deucher@amd.com>
Tue, 26 Sep 2017 21:06:24 +0000 (17:06 -0400)
Signed-off-by: Amy Zhang <Amy.Zhang@amd.com>
Reviewed-by: Aric Cyr <Aric.Cyr@amd.com>
Acked-by: Harry Wentland <Harry.Wentland@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/display/modules/color/color.c
drivers/gpu/drm/amd/display/modules/color/color_helper.h
drivers/gpu/drm/amd/display/modules/inc/mod_color.h

index 6613ff9..9388672 100644 (file)
@@ -63,14 +63,18 @@ struct gamut_src_dst_matrix {
 struct color_state {
        bool user_enable_color_temperature;
        int custom_color_temperature;
-       struct color_space_coordinates source_gamut;
-       struct color_space_coordinates destination_gamut;
        struct color_range contrast;
        struct color_range saturation;
        struct color_range brightness;
        struct color_range hue;
        struct dc_gamma *gamma;
        enum dc_quantization_range preferred_quantization_range;
+
+       struct color_gamut_data source_gamut;
+       struct color_gamut_data destination_gamut;
+       enum color_transfer_func input_transfer_function;
+       enum color_transfer_func output_transfer_function;
+       struct color_mastering_info mastering_info;
 };
 
 struct core_color {
@@ -79,6 +83,7 @@ struct core_color {
        int num_sinks;
        struct sink_caps *caps;
        struct color_state *state;
+       struct color_edid_caps *edid_caps;
 };
 
 #define MOD_COLOR_TO_CORE(mod_color)\
@@ -1286,6 +1291,142 @@ static struct dc_surface *dc_stream_to_surface_from_pipe_ctx(
        return out_surface;
 }
 
+static enum predefined_gamut_type color_space_to_predefined_gamut_types(enum
+               color_color_space color_space)
+{
+       switch (color_space) {
+       case color_space_bt709:
+       case color_space_xv_ycc_bt709:
+               return gamut_type_bt709;
+       case color_space_bt601:
+       case color_space_xv_ycc_bt601:
+               return gamut_type_bt601;
+       case color_space_adobe:
+               return gamut_type_adobe_rgb;
+       case color_space_srgb:
+       case color_space_sc_rgb_ms_ref:
+               return gamut_type_srgb;
+       case color_space_bt2020:
+               return gamut_type_bt2020;
+       case color_space_dci_p3: /* TODO */
+       default:
+               return gamut_type_unknown;
+       }
+}
+
+static enum predefined_white_point_type white_point_to_predefined_white_point
+                               (enum color_white_point_type white_point)
+{
+       switch (white_point) {
+       case color_white_point_type_5000k_horizon:
+               return white_point_type_5000k_horizon;
+       case color_white_point_type_6500k_noon:
+               return white_point_type_6500k_noon;
+       case color_white_point_type_7500k_north_sky:
+               return white_point_type_7500k_north_sky;
+       case color_white_point_type_9300k:
+               return white_point_type_9300k;
+       default:
+               return white_point_type_unknown;
+       }
+}
+
+static bool update_color_gamut_data(struct color_gamut_data *input_data,
+               struct color_gamut_data *output_data)
+{
+       bool output_custom_cs = false;
+       bool output_custom_wp = false;
+
+       if (input_data == NULL || output_data == NULL)
+               return false;
+
+       if (input_data->color_space == color_space_custom_coordinates) {
+               output_data->color_space = input_data->color_space;
+               output_data->gamut.redX = input_data->gamut.redX;
+               output_data->gamut.redY = input_data->gamut.redY;
+               output_data->gamut.greenX = input_data->gamut.greenX;
+               output_data->gamut.greenY = input_data->gamut.greenY;
+               output_data->gamut.blueX = input_data->gamut.blueX;
+               output_data->gamut.blueY = input_data->gamut.blueY;
+       } else {
+               struct gamut_space_coordinates gamut_coord;
+               enum predefined_gamut_type gamut_type =
+                               color_space_to_predefined_gamut_types
+                               (input_data->color_space);
+
+               /* fall back to original color space if unknown */
+               if (gamut_type == gamut_type_unknown) {
+                       if (output_data->color_space ==
+                                       color_space_custom_coordinates) {
+                               output_custom_cs = true;
+                       } else {
+                               gamut_type =
+                                       color_space_to_predefined_gamut_types
+                                       (output_data->color_space);
+                               /* fall back to sRGB if both unknown*/
+                               if (gamut_type == gamut_type_unknown) {
+                                       output_data->color_space =
+                                               color_space_srgb;
+                                       gamut_type = gamut_type_srgb;
+                               }
+                       }
+               } else {
+                       output_data->color_space = input_data->color_space;
+               }
+
+               if (!output_custom_cs) {
+                       mod_color_find_predefined_gamut(&gamut_coord,
+                                       gamut_type);
+                       output_data->gamut.redX = gamut_coord.redX;
+                       output_data->gamut.redY = gamut_coord.redY;
+                       output_data->gamut.greenX = gamut_coord.greenX;
+                       output_data->gamut.greenY = gamut_coord.greenY;
+                       output_data->gamut.blueX = gamut_coord.blueX;
+                       output_data->gamut.blueY = gamut_coord.blueY;
+               }
+       }
+
+       if (input_data->white_point == color_space_custom_coordinates) {
+               output_data->white_point = input_data->white_point;
+               output_data->gamut.whiteX = input_data->gamut.whiteX;
+               output_data->gamut.whiteY = input_data->gamut.whiteY;
+       } else {
+               struct white_point_coodinates white_point_coord;
+               enum predefined_white_point_type white_type =
+                               white_point_to_predefined_white_point
+                               (input_data->white_point);
+
+               /* fall back to original white point if not found */
+               if (white_type == white_point_type_unknown) {
+                       if (output_data->white_point ==
+                               color_white_point_type_custom_coordinates) {
+                               output_custom_wp = true;
+                       } else {
+                               white_type =
+                                       white_point_to_predefined_white_point
+                                       (output_data->white_point);
+                               /* fall back to 6500 if both unknown*/
+                               if (white_type == white_point_type_unknown) {
+                                       output_data->white_point =
+                                       color_white_point_type_6500k_noon;
+                                       white_type =
+                                               white_point_type_6500k_noon;
+                               }
+                       }
+               } else {
+                       output_data->white_point = input_data->white_point;
+               }
+
+               if (!output_custom_wp) {
+                       mod_color_find_predefined_white_point(
+                                       &white_point_coord, white_type);
+                       output_data->gamut.whiteX = white_point_coord.whiteX;
+                       output_data->gamut.whiteY = white_point_coord.whiteY;
+               }
+       }
+       return true;
+}
+
 struct mod_color *mod_color_create(struct dc *dc)
 {
        int i = 0;
@@ -1311,23 +1452,36 @@ struct mod_color *mod_color_create(struct dc *dc)
 
        /*hardcoded to sRGB with 6500 color temperature*/
        for (i = 0; i < MOD_COLOR_MAX_CONCURRENT_SINKS; i++) {
-               core_color->state[i].source_gamut.blueX = 1500;
-               core_color->state[i].source_gamut.blueY = 600;
-               core_color->state[i].source_gamut.greenX = 3000;
-               core_color->state[i].source_gamut.greenY = 6000;
-               core_color->state[i].source_gamut.redX = 6400;
-               core_color->state[i].source_gamut.redY = 3300;
-               core_color->state[i].source_gamut.whiteX = 3127;
-               core_color->state[i].source_gamut.whiteY = 3290;
-
-               core_color->state[i].destination_gamut.blueX = 1500;
-               core_color->state[i].destination_gamut.blueY = 600;
-               core_color->state[i].destination_gamut.greenX = 3000;
-               core_color->state[i].destination_gamut.greenY = 6000;
-               core_color->state[i].destination_gamut.redX = 6400;
-               core_color->state[i].destination_gamut.redY = 3300;
-               core_color->state[i].destination_gamut.whiteX = 3127;
-               core_color->state[i].destination_gamut.whiteY = 3290;
+               core_color->state[i].source_gamut.color_space =
+                               color_space_srgb;
+               core_color->state[i].source_gamut.white_point =
+                               color_white_point_type_6500k_noon;
+               core_color->state[i].source_gamut.gamut.blueX = 1500;
+               core_color->state[i].source_gamut.gamut.blueY = 600;
+               core_color->state[i].source_gamut.gamut.greenX = 3000;
+               core_color->state[i].source_gamut.gamut.greenY = 6000;
+               core_color->state[i].source_gamut.gamut.redX = 6400;
+               core_color->state[i].source_gamut.gamut.redY = 3300;
+               core_color->state[i].source_gamut.gamut.whiteX = 3127;
+               core_color->state[i].source_gamut.gamut.whiteY = 3290;
+
+               core_color->state[i].destination_gamut.color_space =
+                               color_space_srgb;
+               core_color->state[i].destination_gamut.white_point =
+                               color_white_point_type_6500k_noon;
+               core_color->state[i].destination_gamut.gamut.blueX = 1500;
+               core_color->state[i].destination_gamut.gamut.blueY = 600;
+               core_color->state[i].destination_gamut.gamut.greenX = 3000;
+               core_color->state[i].destination_gamut.gamut.greenY = 6000;
+               core_color->state[i].destination_gamut.gamut.redX = 6400;
+               core_color->state[i].destination_gamut.gamut.redY = 3300;
+               core_color->state[i].destination_gamut.gamut.whiteX = 3127;
+               core_color->state[i].destination_gamut.gamut.whiteY = 3290;
+
+               core_color->state[i].input_transfer_function =
+                                               transfer_func_srgb;
+               core_color->state[i].output_transfer_function =
+                                               transfer_func_srgb;
 
                core_color->state[i].custom_color_temperature = 6500;
 
@@ -1351,6 +1505,12 @@ struct mod_color *mod_color_create(struct dc *dc)
        if (core_color->state == NULL)
                goto fail_alloc_state;
 
+       core_color->edid_caps = dm_alloc(sizeof(struct color_edid_caps) *
+                       MOD_COLOR_MAX_CONCURRENT_SINKS);
+
+       if (core_color->edid_caps == NULL)
+               goto fail_alloc_edid_caps;
+
        core_color->num_sinks = 0;
 
        if (dc == NULL)
@@ -1371,6 +1531,9 @@ struct mod_color *mod_color_create(struct dc *dc)
        return &core_color->public;
 
 fail_construct:
+       dm_free(core_color->edid_caps);
+
+fail_alloc_edid_caps:
        dm_free(core_color->state);
 
 fail_alloc_state:
@@ -1390,6 +1553,8 @@ void mod_color_destroy(struct mod_color *mod_color)
                struct core_color *core_color =
                                MOD_COLOR_TO_CORE(mod_color);
 
+               dm_free(core_color->edid_caps);
+
                for (i = 0; i < core_color->num_sinks; i++)
                        if (core_color->state[i].gamma)
                                dc_gamma_release(core_color->state[i].gamma);
@@ -1405,7 +1570,8 @@ void mod_color_destroy(struct mod_color *mod_color)
        }
 }
 
-bool mod_color_add_sink(struct mod_color *mod_color, const struct dc_sink *sink)
+bool mod_color_add_sink(struct mod_color *mod_color, const struct dc_sink *sink,
+               struct color_edid_caps *edid_caps)
 {
        struct core_color *core_color = MOD_COLOR_TO_CORE(mod_color);
        struct core_dc *core_dc = DC_TO_CORE(core_color->dc);
@@ -1426,6 +1592,11 @@ bool mod_color_add_sink(struct mod_color *mod_color, const struct dc_sink *sink)
                core_color->state[core_color->num_sinks].
                                user_enable_color_temperature = true;
 
+               core_color->edid_caps[core_color->num_sinks].colorimetry_caps =
+                               edid_caps->colorimetry_caps;
+               core_color->edid_caps[core_color->num_sinks].hdr_caps =
+                               edid_caps->hdr_caps;
+
                /* get persistent data from registry */
                flag.save_per_edid = true;
                flag.save_per_link = false;
@@ -1462,25 +1633,25 @@ bool mod_color_add_sink(struct mod_color *mod_color, const struct dc_sink *sink)
                                        sizeof(struct color_space_coordinates),
                                        &flag)) {
                        memcpy(&core_color->state[core_color->num_sinks].
-                               source_gamut, &persistent_source_gamut,
+                               source_gamut.gamut, &persistent_source_gamut,
                                sizeof(struct color_space_coordinates));
                } else {
                        core_color->state[core_color->num_sinks].
-                                       source_gamut.blueX = 1500;
+                                       source_gamut.gamut.blueX = 1500;
                        core_color->state[core_color->num_sinks].
-                                       source_gamut.blueY = 600;
+                                       source_gamut.gamut.blueY = 600;
                        core_color->state[core_color->num_sinks].
-                                       source_gamut.greenX = 3000;
+                                       source_gamut.gamut.greenX = 3000;
                        core_color->state[core_color->num_sinks].
-                                       source_gamut.greenY = 6000;
+                                       source_gamut.gamut.greenY = 6000;
                        core_color->state[core_color->num_sinks].
-                                       source_gamut.redX = 6400;
+                                       source_gamut.gamut.redX = 6400;
                        core_color->state[core_color->num_sinks].
-                                       source_gamut.redY = 3300;
+                                       source_gamut.gamut.redY = 3300;
                        core_color->state[core_color->num_sinks].
-                                       source_gamut.whiteX = 3127;
+                                       source_gamut.gamut.whiteX = 3127;
                        core_color->state[core_color->num_sinks].
-                                       source_gamut.whiteY = 3290;
+                                       source_gamut.gamut.whiteY = 3290;
                }
 
                if (dm_read_persistent_data(core_dc->ctx, sink, COLOR_REGISTRY_NAME,
@@ -1489,26 +1660,26 @@ bool mod_color_add_sink(struct mod_color *mod_color, const struct dc_sink *sink)
                                        sizeof(struct color_space_coordinates),
                                        &flag)) {
                        memcpy(&core_color->state[core_color->num_sinks].
-                               destination_gamut,
+                               destination_gamut.gamut,
                                &persistent_destination_gamut,
                                sizeof(struct color_space_coordinates));
                } else {
                        core_color->state[core_color->num_sinks].
-                                       destination_gamut.blueX = 1500;
+                                       destination_gamut.gamut.blueX = 1500;
                        core_color->state[core_color->num_sinks].
-                                       destination_gamut.blueY = 600;
+                                       destination_gamut.gamut.blueY = 600;
                        core_color->state[core_color->num_sinks].
-                                       destination_gamut.greenX = 3000;
+                                       destination_gamut.gamut.greenX = 3000;
                        core_color->state[core_color->num_sinks].
-                                       destination_gamut.greenY = 6000;
+                                       destination_gamut.gamut.greenY = 6000;
                        core_color->state[core_color->num_sinks].
-                                       destination_gamut.redX = 6400;
+                                       destination_gamut.gamut.redX = 6400;
                        core_color->state[core_color->num_sinks].
-                                       destination_gamut.redY = 3300;
+                                       destination_gamut.gamut.redY = 3300;
                        core_color->state[core_color->num_sinks].
-                                       destination_gamut.whiteX = 3127;
+                                       destination_gamut.gamut.whiteX = 3127;
                        core_color->state[core_color->num_sinks].
-                                       destination_gamut.whiteY = 3290;
+                                       destination_gamut.gamut.whiteY = 3290;
                }
 
                if (dm_read_persistent_data(core_dc->ctx, sink, COLOR_REGISTRY_NAME,
@@ -1588,6 +1759,10 @@ bool mod_color_remove_sink(struct mod_color *mod_color,
                                memcpy(&core_color->state[j],
                                        &core_color->state[j + 1],
                                        sizeof(struct color_state));
+
+                               memcpy(&core_color->edid_caps[j],
+                                       &core_color->edid_caps[j + 1],
+                                       sizeof(struct color_edid_caps));
                        }
 
                        core_color->num_sinks--;
@@ -1625,7 +1800,7 @@ bool mod_color_update_gamut_to_stream(struct mod_color *mod_color,
                                        COLOR_REGISTRY_NAME,
                                        "sourcegamut",
                                        &core_color->state[sink_index].
-                                                       source_gamut,
+                                                       source_gamut.gamut,
                                        sizeof(struct color_space_coordinates),
                                        &flag);
 
@@ -1634,19 +1809,19 @@ bool mod_color_update_gamut_to_stream(struct mod_color *mod_color,
                                        COLOR_REGISTRY_NAME,
                                        "destgamut",
                                        &core_color->state[sink_index].
-                                                       destination_gamut,
+                                                       destination_gamut.gamut,
                                        sizeof(struct color_space_coordinates),
                                        &flag);
 
                if (!build_gamut_remap_matrix
-                               (core_color->state[sink_index].source_gamut,
-                                               matrix->rgbCoeffSrc,
-                                               matrix->whiteCoeffSrc))
+                       (core_color->state[sink_index].source_gamut.gamut,
+                                       matrix->rgbCoeffSrc,
+                                       matrix->whiteCoeffSrc))
                        goto function_fail;
 
                if (!build_gamut_remap_matrix
                                (core_color->state[sink_index].
-                               destination_gamut,
+                               destination_gamut.gamut,
                                matrix->rgbCoeffDst, matrix->whiteCoeffDst))
                        goto function_fail;
 
@@ -1700,8 +1875,7 @@ function_fail:
 
 bool mod_color_adjust_source_gamut(struct mod_color *mod_color,
                const struct dc_stream **streams, int num_streams,
-               struct gamut_space_coordinates *input_gamut_coordinates,
-               struct white_point_coodinates *input_white_point_coordinates)
+               struct color_gamut_data *input_gamut_data)
 {
        struct core_color *core_color = MOD_COLOR_TO_CORE(mod_color);
 
@@ -1711,25 +1885,35 @@ bool mod_color_adjust_source_gamut(struct mod_color *mod_color,
                sink_index = sink_index_from_sink(core_color,
                                streams[stream_index]->sink);
 
-               core_color->state[sink_index].source_gamut.blueX =
-                               input_gamut_coordinates->blueX;
-               core_color->state[sink_index].source_gamut.blueY =
-                               input_gamut_coordinates->blueY;
-               core_color->state[sink_index].source_gamut.greenX =
-                               input_gamut_coordinates->greenX;
-               core_color->state[sink_index].source_gamut.greenY =
-                               input_gamut_coordinates->greenY;
-               core_color->state[sink_index].source_gamut.redX =
-                               input_gamut_coordinates->redX;
-               core_color->state[sink_index].source_gamut.redY =
-                               input_gamut_coordinates->redY;
-               core_color->state[sink_index].source_gamut.whiteX =
-                               input_white_point_coordinates->whiteX;
-               core_color->state[sink_index].source_gamut.whiteY =
-                               input_white_point_coordinates->whiteY;
+               update_color_gamut_data(input_gamut_data,
+                               &core_color->state[sink_index].source_gamut);
        }
 
-       if (!mod_color_update_gamut_to_stream(mod_color, streams, num_streams))
+       if (!mod_color_update_gamut_info(mod_color, streams, num_streams))
+               return false;
+
+       return true;
+}
+
+bool mod_color_adjust_source_gamut_and_tf(struct mod_color *mod_color,
+               const struct dc_stream **streams, int num_streams,
+               struct color_gamut_data *input_gamut_data,
+               enum color_transfer_func input_transfer_func)
+{
+       struct core_color *core_color = MOD_COLOR_TO_CORE(mod_color);
+
+       unsigned int stream_index, sink_index;
+
+       for (stream_index = 0; stream_index < num_streams; stream_index++) {
+               sink_index = sink_index_from_sink(core_color,
+                               streams[stream_index]->sink);
+               update_color_gamut_data(input_gamut_data,
+                               &core_color->state[sink_index].source_gamut);
+               core_color->state[sink_index].input_transfer_function =
+                               input_transfer_func;
+       }
+
+       if (!mod_color_update_gamut_info(mod_color, streams, num_streams))
                return false;
 
        return true;
@@ -1737,8 +1921,7 @@ bool mod_color_adjust_source_gamut(struct mod_color *mod_color,
 
 bool mod_color_adjust_destination_gamut(struct mod_color *mod_color,
                const struct dc_stream **streams, int num_streams,
-               struct gamut_space_coordinates *input_gamut_coordinates,
-               struct white_point_coodinates *input_white_point_coordinates)
+               struct color_gamut_data *input_gamut_data)
 {
        struct core_color *core_color = MOD_COLOR_TO_CORE(mod_color);
 
@@ -1748,22 +1931,8 @@ bool mod_color_adjust_destination_gamut(struct mod_color *mod_color,
                sink_index = sink_index_from_sink(core_color,
                                streams[stream_index]->sink);
 
-               core_color->state[sink_index].destination_gamut.blueX =
-                               input_gamut_coordinates->blueX;
-               core_color->state[sink_index].destination_gamut.blueY =
-                               input_gamut_coordinates->blueY;
-               core_color->state[sink_index].destination_gamut.greenX =
-                               input_gamut_coordinates->greenX;
-               core_color->state[sink_index].destination_gamut.greenY =
-                               input_gamut_coordinates->greenY;
-               core_color->state[sink_index].destination_gamut.redX =
-                               input_gamut_coordinates->redX;
-               core_color->state[sink_index].destination_gamut.redY =
-                               input_gamut_coordinates->redY;
-               core_color->state[sink_index].destination_gamut.whiteX =
-                               input_white_point_coordinates->whiteX;
-               core_color->state[sink_index].destination_gamut.whiteY =
-                               input_white_point_coordinates->whiteY;
+               update_color_gamut_data(input_gamut_data,
+                       &core_color->state[sink_index].destination_gamut);
        }
 
        if (!mod_color_update_gamut_to_stream(mod_color, streams, num_streams))
@@ -1784,9 +1953,9 @@ bool mod_color_set_white_point(struct mod_color *mod_color,
                        stream_index++) {
                sink_index = sink_index_from_sink(core_color,
                                streams[stream_index]->sink);
-               core_color->state[sink_index].source_gamut.whiteX =
+               core_color->state[sink_index].source_gamut.gamut.whiteX =
                                white_point->whiteX;
-               core_color->state[sink_index].source_gamut.whiteY =
+               core_color->state[sink_index].source_gamut.gamut.whiteY =
                                white_point->whiteY;
        }
 
@@ -1796,6 +1965,39 @@ bool mod_color_set_white_point(struct mod_color *mod_color,
        return true;
 }
 
+
+bool mod_color_set_mastering_info(struct mod_color *mod_color,
+               const struct dc_stream **streams, int num_streams,
+               struct color_mastering_info *mastering_info)
+{
+       struct core_color *core_color = MOD_COLOR_TO_CORE(mod_color);
+       unsigned int stream_index, sink_index;
+
+       for (stream_index = 0; stream_index < num_streams; stream_index++) {
+               sink_index = sink_index_from_sink(core_color,
+                               streams[stream_index]->sink);
+               memcpy(&core_color->state[sink_index].mastering_info,
+                               mastering_info,
+                               sizeof(struct color_mastering_info));
+       }
+       return true;
+}
+
+bool mod_color_get_mastering_info(struct mod_color *mod_color,
+               const struct dc_sink *sink,
+               struct color_mastering_info *mastering_info)
+{
+       struct core_color *core_color =
+                       MOD_COLOR_TO_CORE(mod_color);
+
+       unsigned int sink_index = sink_index_from_sink(core_color, sink);
+
+       memcpy(mastering_info, &core_color->state[sink_index].mastering_info,
+                       sizeof(struct color_mastering_info));
+
+       return true;
+}
+
 bool mod_color_set_user_enable(struct mod_color *mod_color,
                const struct dc_stream **streams, int num_streams,
                bool user_enable)
@@ -1953,7 +2155,7 @@ bool mod_color_get_source_gamut(struct mod_color *mod_color,
 
        unsigned int sink_index = sink_index_from_sink(core_color, sink);
 
-       *source_gamut = core_color->state[sink_index].source_gamut;
+       *source_gamut = core_color->state[sink_index].source_gamut.gamut;
 
        return true;
 }
@@ -1973,14 +2175,14 @@ bool mod_color_notify_mode_change(struct mod_color *mod_color,
                                streams[stream_index]->sink);
 
                if (!build_gamut_remap_matrix
-                               (core_color->state[sink_index].source_gamut,
-                                               matrix->rgbCoeffSrc,
-                                               matrix->whiteCoeffSrc))
+                       (core_color->state[sink_index].source_gamut.gamut,
+                                       matrix->rgbCoeffSrc,
+                                       matrix->whiteCoeffSrc))
                        goto function_fail;
 
                if (!build_gamut_remap_matrix
                                (core_color->state[sink_index].
-                               destination_gamut,
+                               destination_gamut.gamut,
                                matrix->rgbCoeffDst, matrix->whiteCoeffDst))
                        goto function_fail;
 
@@ -2379,3 +2581,200 @@ bool mod_color_is_rgb_limited_range_supported_for_timing(
 
        return result;
 }
+
+bool mod_color_set_regamma(struct mod_color *mod_color,
+               const struct dc_stream **streams, int num_streams)
+{
+       /*TODO*/
+       return true;
+}
+
+bool mod_color_set_degamma(struct mod_color *mod_color,
+               const struct dc_stream **streams, int num_streams,
+               enum color_transfer_func transfer_function)
+{
+       /*TODO*/
+       return true;
+}
+
+bool mod_color_update_gamut_info(struct mod_color *mod_color,
+               const struct dc_stream **streams, int num_streams)
+{
+       struct core_color *core_color = MOD_COLOR_TO_CORE(mod_color);
+       unsigned int stream_index, sink_index;
+       bool should_defer = false;
+       bool is_hdr = false;
+       enum color_color_space source_color_space;
+       enum color_transfer_func input_transfer_function;
+       struct color_gamut_data new_gamut_source;
+       struct color_gamut_data new_gamut_destination;
+
+       for (stream_index = 0; stream_index < num_streams; stream_index++) {
+               sink_index = sink_index_from_sink(core_color,
+                               streams[stream_index]->sink);
+               source_color_space =
+                       core_color->state[sink_index].source_gamut.color_space;
+               input_transfer_function =
+                       core_color->state[sink_index].input_transfer_function;
+               new_gamut_source.color_space = source_color_space;
+               new_gamut_destination.color_space =
+                       core_color->state[sink_index].
+                       destination_gamut.color_space;
+
+               struct dc_surface *surface =
+                       dc_stream_to_surface_from_pipe_ctx(core_color,
+                                       streams[stream_index]);
+               if (surface == NULL)
+                       return false;
+
+               if (surface->format == SURFACE_PIXEL_FORMAT_GRPH_ARGB8888 ||
+                               surface->format ==
+                                       SURFACE_PIXEL_FORMAT_GRPH_ARGB2101010) {
+
+                       if (input_transfer_function ==
+                                       transfer_func_pq2084 ||
+                                       input_transfer_function ==
+                                               transfer_func_pq2084_interim) {
+                               /* For PQ and PQ interim, we bypass degamma+
+                                * remap+regamma, application needs to also
+                                * handle gamut remapping
+                                */
+                               /* TODO */
+                               is_hdr = true;
+                       } else if (input_transfer_function ==
+                                       transfer_func_linear_0_1 ||
+                                       input_transfer_function ==
+                                               transfer_func_linear_0_125) {
+                               /* TF not supported in current surface format,
+                                * but may be deferred to a later flip
+                                */
+                               should_defer = true;
+                       } else {
+                               new_gamut_destination.color_space =
+                                                       color_space_srgb;
+                       }
+               } else if (surface->format ==
+                               SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F ||
+                               surface->format ==
+                               SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F ||
+                               surface->format ==
+                               SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616) {
+                       if (input_transfer_function ==
+                                       transfer_func_linear_0_125) {
+                               /* Regamma PQ for HDR supported displays and
+                               * 0-125 source
+                               */
+                               if ((core_color->edid_caps[sink_index].
+                                       hdr_caps) & smpte_st2084)
+                                       is_hdr = true;
+
+                               /* override for BT.2020 whenever PQ */
+                               if (core_color->state[sink_index].
+                                       destination_gamut.color_space !=
+                                               color_space_bt2020) {
+                                       if (streams[stream_index]->timing.
+                                               pixel_encoding ==
+                                               PIXEL_ENCODING_RGB) {
+                                               if ((core_color->
+                                               edid_caps[sink_index].
+                                               colorimetry_caps) & bt_2020_rgb)
+                                                       new_gamut_destination.
+                                                       color_space =
+                                                       color_space_bt2020;
+                                       } else {
+                                               if ((core_color->
+                                               edid_caps[sink_index].
+                                               colorimetry_caps) & bt_2020_ycc)
+                                                       new_gamut_destination.
+                                                       color_space =
+                                                       color_space_bt2020;
+                                       }
+                               }
+                       } else if (input_transfer_function ==
+                                       transfer_func_linear_0_1) {
+                               new_gamut_destination.color_space =
+                                               color_space_srgb;
+                       } else {
+                               /* TF not supported in current surface format,
+                               * but may be deferred to a later flip
+                               */
+                               should_defer = true;
+                       }
+               }
+
+               /* 0. ---- CHECK DEFERRED ---- */
+               if (should_defer)
+                       return true;
+
+               /* 1. ---- SET GAMUT SOURCE ---- */
+               new_gamut_source.white_point = core_color->state[sink_index].
+                               source_gamut.white_point;
+               update_color_gamut_data(&new_gamut_source,
+                       &core_color->state[sink_index].source_gamut);
+
+               /* 2. ---- SET GAMUT DESTINATION ---- */
+               new_gamut_destination.white_point =
+                               core_color->state[sink_index].
+                               destination_gamut.white_point;
+               update_color_gamut_data(&new_gamut_destination,
+                       &core_color->state[sink_index].destination_gamut);
+
+               /* 3. ---- SET DEGAMMA ---- */
+               struct dc_transfer_func *input_tf = NULL;
+
+               input_tf = dc_create_transfer_func(core_color->dc);
+
+               if (input_tf != NULL) {
+                       input_tf->type = TF_TYPE_PREDEFINED;
+
+                       switch (input_transfer_function) {
+                       case transfer_func_srgb:
+                               input_tf->tf = TRANSFER_FUNCTION_SRGB;
+                               break;
+                       case transfer_func_linear_0_1:
+                       case transfer_func_linear_0_125:
+                               input_tf->tf = TRANSFER_FUNCTION_LINEAR;
+                               break;
+                       default:
+                               dc_transfer_func_release(input_tf);
+                               input_tf = NULL;
+                               break;
+                       }
+               }
+
+               /* 4. ---- SET REGAMMA ---- */
+               struct dc_transfer_func *output_tf = NULL;
+
+               output_tf = dc_create_transfer_func(core_color->dc);
+
+               if (output_tf != NULL) {
+                       output_tf->type = TF_TYPE_PREDEFINED;
+                       if (is_hdr)
+                               output_tf->tf = TRANSFER_FUNCTION_PQ;
+                       else
+                               output_tf->tf = TRANSFER_FUNCTION_SRGB;
+               }
+
+               /* 5. ---- TODO: UPDATE INFOPACKETS ---- */
+
+               if (!mod_color_update_gamut_to_stream(
+                               mod_color, streams, num_streams))
+                       return false;
+
+               struct dc_surface_update updates[4] = {0};
+
+               updates[0].surface = surface;
+               updates[0].gamma = core_color->state[sink_index].gamma;
+               updates[0].in_transfer_func = input_tf;
+               updates[0].out_transfer_func = output_tf;
+
+               dc_update_surfaces_for_target(core_color->dc, updates, 1, NULL);
+
+               if (input_tf != NULL)
+                       dc_transfer_func_release(input_tf);
+
+               if (output_tf != NULL)
+                       dc_transfer_func_release(output_tf);
+       }
+       return true;
+}
index c0e6334..b7a7ca4 100644 (file)
@@ -37,7 +37,7 @@ bool mod_color_find_predefined_gamut(
 
 bool mod_color_find_predefined_white_point(
                struct white_point_coodinates *out_white_point,
-               unsigned int index);
+               enum predefined_white_point_type type);
 
 bool mod_color_find_white_point_from_temperature(
                struct white_point_coodinates *out_white_point,
index fbf9081..670b87f 100644 (file)
 #include "dm_services.h"
 #include "color_helper.h"
 
+enum color_transfer_func {
+       transfer_func_unknown,
+       transfer_func_srgb,
+       transfer_func_bt709,
+       transfer_func_pq2084,
+       transfer_func_pq2084_interim,
+       transfer_func_linear_0_1,
+       transfer_func_linear_0_125,
+       transfer_func_dolbyvision,
+       transfer_func_gamma_22,
+       transfer_func_gamma_26
+};
+
+enum color_color_space {
+       color_space_unsupported,
+       color_space_srgb,
+       color_space_bt601,
+       color_space_bt709,
+       color_space_xv_ycc_bt601,
+       color_space_xv_ycc_bt709,
+       color_space_xr_rgb,
+       color_space_bt2020,
+       color_space_adobe,
+       color_space_dci_p3,
+       color_space_sc_rgb_ms_ref,
+       color_space_display_native,
+       color_space_app_ctrl,
+       color_space_dolby_vision,
+       color_space_custom_coordinates
+};
+
+enum color_white_point_type {
+       color_white_point_type_unknown,
+       color_white_point_type_5000k_horizon,
+       color_white_point_type_6500k_noon,
+       color_white_point_type_7500k_north_sky,
+       color_white_point_type_9300k,
+       color_white_point_type_custom_coordinates
+};
+
+enum colorimetry_support_flag {
+       xv_ycc_bt601 = 0x01,
+       xv_ycc_bt709 = 0x02,
+       s_ycc_601 = 0x04,
+       adobe_ycc_601 = 0x08,
+       adobe_rgb = 0x10,
+       bt_2020_c_ycc = 0x20,
+       bt_2020_ycc = 0x40,
+       bt_2020_rgb = 0x80
+};
+
+enum hdr_tf_support_flag {
+       traditional_gamma_sdr = 0x01,
+       traditional_gamma_hdr = 0x02,
+       smpte_st2084 = 0x04
+};
+
+struct color_mastering_info {
+       unsigned int chromaticity_green_x;
+       unsigned int chromaticity_green_y;
+       unsigned int chromaticity_blue_x;
+       unsigned int chromaticity_blue_y;
+       unsigned int chromaticity_red_x;
+       unsigned int chromaticity_red_y;
+       unsigned int chromaticity_white_point_x;
+       unsigned int chromaticity_white_point_y;
+
+       unsigned int min_luminance;
+       unsigned int max_luminance;
+       unsigned int maximum_content_light_level;
+       unsigned int maximum_frame_average_light_level;
+};
+
 struct mod_color {
        int dummy;
 };
@@ -86,12 +159,23 @@ struct color_range {
        int max;
 };
 
+struct color_gamut_data {
+       enum color_color_space color_space;
+       enum color_white_point_type white_point;
+       struct color_space_coordinates gamut;
+};
+
+struct color_edid_caps {
+       unsigned int colorimetry_caps;
+       unsigned int hdr_caps;
+};
+
 struct mod_color *mod_color_create(struct dc *dc);
 
 void mod_color_destroy(struct mod_color *mod_color);
 
 bool mod_color_add_sink(struct mod_color *mod_color,
-               const struct dc_sink *sink);
+               const struct dc_sink *sink, struct color_edid_caps *edid_caps);
 
 bool mod_color_remove_sink(struct mod_color *mod_color,
                const struct dc_sink *sink);
@@ -105,18 +189,29 @@ bool mod_color_set_white_point(struct mod_color *mod_color,
 
 bool mod_color_adjust_source_gamut(struct mod_color *mod_color,
                const struct dc_stream **streams, int num_streams,
-               struct gamut_space_coordinates *input_gamut_coordinates,
-               struct white_point_coodinates *input_white_point_coordinates);
+               struct color_gamut_data *input_gamut_data);
 
 bool mod_color_adjust_destination_gamut(struct mod_color *mod_color,
                const struct dc_stream **streams, int num_streams,
-               struct gamut_space_coordinates *input_gamut_coordinates,
-               struct white_point_coodinates *input_white_point_coordinates);
+               struct color_gamut_data *input_gamut_data);
+
+bool mod_color_adjust_source_gamut_and_tf(struct mod_color *mod_color,
+               const struct dc_stream **streams, int num_streams,
+               struct color_gamut_data *input_gamut_data,
+               enum color_transfer_func input_transfer_func);
 
 bool mod_color_get_user_enable(struct mod_color *mod_color,
                const struct dc_sink *sink,
                bool *user_enable);
 
+bool mod_color_set_mastering_info(struct mod_color *mod_color,
+               const struct dc_stream **streams, int num_streams,
+               struct color_mastering_info *mastering_info);
+
+bool mod_color_get_mastering_info(struct mod_color *mod_color,
+               const struct dc_sink *sink,
+               struct color_mastering_info *mastering_info);
+
 bool mod_color_set_user_enable(struct mod_color *mod_color,
                const struct dc_stream **streams, int num_streams,
                bool user_enable);
@@ -190,4 +285,14 @@ bool mod_color_is_rgb_limited_range_supported_for_timing(
                const struct dc_sink *sink,
                const struct dc_crtc_timing *timing);
 
+bool mod_color_set_regamma(struct mod_color *mod_color,
+               const struct dc_stream **streams, int num_streams);
+
+bool mod_color_set_degamma(struct mod_color *mod_color,
+               const struct dc_stream **streams, int num_streams,
+               enum color_transfer_func transfer_function);
+
+bool mod_color_update_gamut_info(struct mod_color *mod_color,
+               const struct dc_stream **streams, int num_streams);
+
 #endif /* MOD_COLOR_H_ */