Commit 78e4405c authored by David Francis's avatar David Francis Committed by Alex Deucher
Browse files

drm/amd/display: Implement custom degamma lut on dcn



[Why]
Custom degamma lut functions are a feature we would
like to support on compatible hardware

[How]
In atomic check, convert from array of drm_color_lut to
dc_transfer_func.  On hardware commit, allow for possibility
of custom degamma.  Both are based on the equivalent
regamma pipeline.

Signed-off-by: default avatarDavid Francis <David.Francis@amd.com>
Reviewed-by: default avatarKrunoslav Kovac <Krunoslav.Kovac@amd.com>
Acked-by: default avatarBhawanpreet Lakha <Bhawanpreet.Lakha@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent d90e9a3b
Loading
Loading
Loading
Loading
+32 −10
Original line number Diff line number Diff line
@@ -231,18 +231,21 @@ void amdgpu_dm_set_ctm(struct dm_crtc_state *crtc)
 * preparation for hardware commit. If no lut is specified by user, we default
 * to SRGB degamma.
 *
 * Currently, we only support degamma bypass, or preprogrammed SRGB degamma.
 * Programmable degamma is not supported, and an attempt to do so will return
 * -EINVAL.
 * We support degamma bypass, predefined SRGB, and custom degamma
 *
 * RETURNS:
 * 0 on success, -EINVAL if custom degamma curve is given.
 * 0 on success
 * -EINVAL if crtc_state has a degamma_lut of invalid size
 * -ENOMEM if gamma allocation fails
 */
int amdgpu_dm_set_degamma_lut(struct drm_crtc_state *crtc_state,
			      struct dc_plane_state *dc_plane_state)
{
	struct drm_property_blob *blob = crtc_state->degamma_lut;
	struct drm_color_lut *lut;
	uint32_t lut_size;
	struct dc_gamma *gamma;
	bool ret;

	if (!blob) {
		/* Default to SRGB */
@@ -258,11 +261,30 @@ int amdgpu_dm_set_degamma_lut(struct drm_crtc_state *crtc_state,
		return 0;
	}

	/* Otherwise, assume SRGB, since programmable degamma is not
	 * supported.
	 */
	dc_plane_state->in_transfer_func->type = TF_TYPE_PREDEFINED;
	dc_plane_state->in_transfer_func->tf = TRANSFER_FUNCTION_SRGB;
	gamma = dc_create_gamma();
	if (!gamma)
		return -ENOMEM;

	lut_size = blob->length / sizeof(struct drm_color_lut);
	gamma->num_entries = lut_size;
	if (gamma->num_entries == MAX_COLOR_LUT_ENTRIES)
		gamma->type = GAMMA_CUSTOM;
	else {
		dc_gamma_release(&gamma);
		return -EINVAL;
	}

	__drm_lut_to_dc_gamma(lut, gamma, false);

	dc_plane_state->in_transfer_func->type = TF_TYPE_DISTRIBUTED_POINTS;
	ret = mod_color_calculate_degamma_params(dc_plane_state->in_transfer_func, gamma, true);
	dc_gamma_release(&gamma);
	if (!ret) {
		dc_plane_state->in_transfer_func->type = TF_TYPE_BYPASS;
		DRM_ERROR("Out of memory when calculating degamma params\n");
		return -ENOMEM;
	}

	return 0;
}
+2 −0
Original line number Diff line number Diff line
@@ -417,6 +417,7 @@ enum {
	GAMMA_RGB_256_ENTRIES = 256,
	GAMMA_RGB_FLOAT_1024_ENTRIES = 1024,
	GAMMA_CS_TFM_1D_ENTRIES = 4096,
	GAMMA_CUSTOM_ENTRIES = 4096,
	GAMMA_MAX_ENTRIES = 4096
};

@@ -424,6 +425,7 @@ enum dc_gamma_type {
	GAMMA_RGB_256 = 1,
	GAMMA_RGB_FLOAT_1024 = 2,
	GAMMA_CS_TFM_1D = 3,
	GAMMA_CUSTOM = 4,
};

struct dc_csc_transform {
+5 −2
Original line number Diff line number Diff line
@@ -1213,8 +1213,11 @@ static bool dcn10_set_input_transfer_func(struct pipe_ctx *pipe_ctx,
	} else if (tf->type == TF_TYPE_BYPASS) {
		dpp_base->funcs->dpp_set_degamma(dpp_base, IPP_DEGAMMA_MODE_BYPASS);
	} else {
		/*TF_TYPE_DISTRIBUTED_POINTS*/
		result = false;
		cm_helper_translate_curve_to_degamma_hw_format(tf,
					&dpp_base->degamma_params);
		dpp_base->funcs->dpp_program_degamma_pwl(dpp_base,
				&dpp_base->degamma_params);
		result = true;
	}

	return result;
+7 −3
Original line number Diff line number Diff line
@@ -998,6 +998,8 @@ static void scale_user_regamma_ramp(struct pwl_float_data *pwl_rgb,
 * lut1 = lut1D[index], lut2 = lut1D[index+1]
 *
 * adjustedY is then linearly interpolating regamma Y between lut1 and lut2
 *
 * Custom degamma on Linux uses the same interpolation math, so is handled here
 */
static void apply_lut_1d(
		const struct dc_gamma *ramp,
@@ -1018,7 +1020,7 @@ static void apply_lut_1d(
	struct fixed31_32 delta_lut;
	struct fixed31_32 delta_index;

	if (ramp->type != GAMMA_CS_TFM_1D)
	if (ramp->type != GAMMA_CS_TFM_1D && ramp->type != GAMMA_CUSTOM)
		return; // this is not expected

	for (i = 0; i < num_hw_points; i++) {
@@ -1636,7 +1638,9 @@ bool mod_color_calculate_degamma_params(struct dc_transfer_func *input_tf,
	map_regamma_hw_to_x_user(ramp, coeff, rgb_user,
			coordinates_x, axix_x, curve,
			MAX_HW_POINTS, tf_pts,
			mapUserRamp);
			mapUserRamp && ramp->type != GAMMA_CUSTOM);
	if (ramp->type == GAMMA_CUSTOM)
		apply_lut_1d(ramp, MAX_HW_POINTS, tf_pts);

	ret = true;