blob: f8a65b41200d05a6dbfb3354f53dd68af764337a [file] [log] [blame]
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* drivers/amlogic/media/enhancement/amvecm/hdr/am_hdr10_plus_ootf.c
*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
*/
/* Standard Linux headers */
#include <linux/types.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/debugfs.h>
#include <linux/uaccess.h>
#include <linux/amlogic/media/vout/vout_notify.h>
#include <linux/amlogic/media/vfm/vframe_provider.h>
#include <linux/amlogic/media/vfm/vframe_receiver.h>
#include <linux/amlogic/media/amvecm/amvecm.h>
#include "../arch/vpp_hdr_regs.h"
#include "am_hdr10_plus.h"
#include "am_hdr10_plus_ootf.h"
#include "../set_hdr2_v0.h"
unsigned int hdr10_plus_printk;
module_param(hdr10_plus_printk, uint, 0664);
MODULE_PARM_DESC(hdr10_plus_printk, "hdr10_plus_printk");
unsigned int force_ref_peak;
module_param(force_ref_peak, uint, 0664);
MODULE_PARM_DESC(force_ref_peak, "force_ref_peak");
#define pr_hdr(fmt, args...)\
do {\
if (hdr10_plus_printk)\
pr_info(fmt, ## args);\
} while (0)
/*EBZCurveParameters to gen OOTF bezier curves*/
void ebzcurveparametersinit(struct ebzcurveparameters *ebzcurveparameters)
{
int i;
ebzcurveparameters->sx = 0;
ebzcurveparameters->sy = 0;
ebzcurveparameters->order = N;
for (i = 0; i < N; i++)
ebzcurveparameters->anchor[i] = PORCESSING_DATA_MAX;
}
/*percentile actually obtained from metadata */
void percentileinit(struct percentiles *percentile,
struct hdr10_plus_sei_s *hdr10_plus_sei)
{
int i;
percentile->num_percentile = hdr10_plus_sei->num_distributions[0];
for (i = 0; i < percentile->num_percentile; i++) {
percentile->percentilepercent[i] =
hdr10_plus_sei->distribution_index[0][i];
percentile->percentilevalue[i] =
hdr10_plus_sei->distribution_values[0][i] / 10;
}
}
/*metadata should obtained from 3C or 2094 metadata*/
void metadatainit(struct scene2094metadata *metadata,
struct hdr10_plus_sei_s *hdr10_plus_sei)
{
int i;
int found99percentage = 0;
for (i = 0; i < hdr10_plus_sei->num_distributions[0]; i++) {
if (hdr10_plus_sei->distribution_index[0][i] == 99)
found99percentage = 1;
}
/*hdmitx vsif block have no maxscl,we can choose distribution value[8]*/
/*if (!metadata->maxscenesourceluminance)*/
/* from samsung sdk code, it used distribution first,*/
/* if no 99 percentage, it will select maxscl*/
if (found99percentage &&
hdr10_plus_sei->distribution_values[0][8] != 0)
metadata->maxscenesourceluminance =
hdr10_plus_sei->distribution_values[0][8] / 10;
else
metadata->maxscenesourceluminance =
max(max(hdr10_plus_sei->maxscl[0][0],
hdr10_plus_sei->maxscl[0][1]),
hdr10_plus_sei->maxscl[0][2]) / 10;
metadata->minluminance = MIN_LUMINANCE;
metadata->referenceluminance =
hdr10_plus_sei->targeted_system_display_maximum_luminance;
percentileinit(&metadata->percentiles, hdr10_plus_sei);
metadata->ebzcurveparameters.sx = hdr10_plus_sei->knee_point_x[0];
metadata->ebzcurveparameters.sy = hdr10_plus_sei->knee_point_y[0];
metadata->ebzcurveparameters.order =
hdr10_plus_sei->num_bezier_curve_anchors[0];
for (i = 0; i < N - 1; i++)
metadata->ebzcurveparameters.anchor[i] =
hdr10_plus_sei->bezier_curve_anchors[0][i];
}
/* get EBZcurve params from metadata.*/
void getmetadata(struct scene2094metadata *metadata,
struct ebzcurveparameters *referencebezierparams)
{
int i;
if (metadata->ebzcurveparameters.order) {
referencebezierparams->order =
metadata->ebzcurveparameters.order + 1;
referencebezierparams->sy = metadata->ebzcurveparameters.sy;
referencebezierparams->sx = metadata->ebzcurveparameters.sx;
for (i = 0; i < referencebezierparams->order; i++)
referencebezierparams->anchor[i] =
metadata->ebzcurveparameters.anchor[i];
} else {
referencebezierparams->order = 10;
}
}
/*TV side default setting: bezier curve params to gen basic OOTF curve*/
void basisootf_params_init(struct basisootf_params *basisootf_params)
{
int p2top9_max1_init[ORDER - 2] = {
0.5582 * PORCESSING_DATA_MAX, 0.6745 * PORCESSING_DATA_MAX,
0.7703 * PORCESSING_DATA_MAX, 0.8231 * PORCESSING_DATA_MAX,
0.8729 * PORCESSING_DATA_MAX, 0.9130 * PORCESSING_DATA_MAX,
0.9599 * PORCESSING_DATA_MAX, 0.9844 * PORCESSING_DATA_MAX
};
int p2top9_max2_init[ORDER - 2] = {
0.4839 * PORCESSING_DATA_MAX, 0.6325 * PORCESSING_DATA_MAX,
0.7253 * PORCESSING_DATA_MAX, 0.7722 * PORCESSING_DATA_MAX,
0.8201 * PORCESSING_DATA_MAX, 0.8837 * PORCESSING_DATA_MAX,
0.9208 * PORCESSING_DATA_MAX, 0.9580 * PORCESSING_DATA_MAX
};
int i;
/*u12*/
basisootf_params->SY1_V1 = 0 << (PROCESSING_MAX - 12);
basisootf_params->SY1_V2 = 1229 << (PROCESSING_MAX - 12);
basisootf_params->SY1_T1 = 901 << (PROCESSING_MAX - 12);
basisootf_params->SY1_T2 = 4095 << (PROCESSING_MAX - 12);
basisootf_params->SY2_V1 = 0 << (PROCESSING_MAX - 12);
basisootf_params->SY2_V2 = 819 << (PROCESSING_MAX - 12);
basisootf_params->SY2_T1 = 1024 << (PROCESSING_MAX - 12);
basisootf_params->SY2_T2 = 3890 << (PROCESSING_MAX - 12);
/* KP mixing gain (final KP from bounds KP # 1 and KP # 2*/
/*as a function of scene percentile) */
basisootf_params->KP_G_V1 = 4095 << (PROCESSING_MAX - 12);
basisootf_params->KP_G_V2 = 205 << (PROCESSING_MAX - 12);
basisootf_params->KP_G_T1 = 205 << (PROCESSING_MAX - 12);
basisootf_params->KP_G_T2 = 2048 << (PROCESSING_MAX - 12);
/*Thresholds of minimum bound of P1 coefficient*/
basisootf_params->P1_LIMIT_V1 = 3767 << (PROCESSING_MAX - 12);
basisootf_params->P1_LIMIT_V2 = 4013 << (PROCESSING_MAX - 12);
basisootf_params->P1_LIMIT_T1 = 41 << (PROCESSING_MAX - 12);
basisootf_params->P1_LIMIT_T2 = 410 << (PROCESSING_MAX - 12);
/*Thresholds to compute relative shape of curve (P2~P9 coefficient)*/
/*by pre-defined bounds - as a function of scene percentile*/
basisootf_params->P2TO9_T1 = 205 << (PROCESSING_MAX - 12);
basisootf_params->P2TO9_T2 = 2252 << (PROCESSING_MAX - 12);
for (i = 0; i < (ORDER - 2); i++) {
basisootf_params->P2TOP9_MAX1[i] = p2top9_max1_init[i];
basisootf_params->P2TOP9_MAX2[i] = p2top9_max2_init[i];
}
/*Ps mixing gain (obtain all Ps coefficients) -*/
/*as a function of TM dynamic compression ratio*/
basisootf_params->PS_G_T1 = 512 << (PROCESSING_MAX - 12);
basisootf_params->PS_G_T2 = 3890 << (PROCESSING_MAX - 12);
/*Post-processing : Reduce P1/P2 (to enhance mid tone)*/
/*for high TM dynamic range compression cases*/
basisootf_params->LOW_SY_T1 = 20 << (PROCESSING_MAX - 12);
basisootf_params->LOW_SY_T2 = 164 << (PROCESSING_MAX - 12);
basisootf_params->LOW_K_T1 = 491 << (PROCESSING_MAX - 12);
basisootf_params->LOW_K_T2 = 1638 << (PROCESSING_MAX - 12);
basisootf_params->RED_P1_V1 = 2662 << (PROCESSING_MAX - 12);
basisootf_params->RED_P1_T1 = 410 << (PROCESSING_MAX - 12);
basisootf_params->RED_P1_T2 = 3071 << (PROCESSING_MAX - 12);
basisootf_params->RED_P2_V1 = 3276 << (PROCESSING_MAX - 12);
basisootf_params->RED_P2_T1 = 410 << (PROCESSING_MAX - 12);
basisootf_params->RED_P2_T2 = 3071 << (PROCESSING_MAX - 12);
}
/*obtain percentile info on psl50 and psl99,*/
/*to calculate content average level and distribution later*/
void getpercentile_50_99(struct percentiles *scenepercentiles,
int *psll50, int *psll99)
{
int i;
int npsll = PERCENTILE_ORDER;
int delta;
/*Find exact percentiles if provided , else interpolate*/
int psll50_1 = -1, per50_1 = -1;
int psll50_2 = -1, per50_2 = -1;
int psll99_1 = -1, per99_1 = -1;
int psll99_2 = -1, per99_2 = -1;
/* Search for exact percent index or bounds*/
int curpercent = 0, prevpercent = 0;
int curpsll = 0, prevpsll = 0;
/*Set output to -1 (invalid)*/
*psll50 = -1;
*psll99 = -1;
for (i = 0; i < npsll; i++) {
if (i == 1 || i == 2)
continue;
curpercent = scenepercentiles->percentilepercent[i];
curpsll = scenepercentiles->percentilevalue[i];
if (curpercent == 50) {
*psll50 = curpsll;
} else if (*psll50 == -1 &&
curpercent > 50 &&
prevpercent < 50) {
per50_1 = prevpercent;
per50_2 = curpercent;
psll50_1 = prevpsll;
psll50_2 = curpsll;
}
if (curpercent == 99) {
*psll99 = curpsll;
} else if (*psll99 == -1 && curpercent > 99 &&
prevpercent < 99) {
per99_1 = prevpercent;
per99_2 = curpercent;
psll99_1 = prevpsll;
psll99_2 = curpsll;
}
prevpercent = curpercent;
prevpsll = curpsll;
}
if (*psll50 == -1) {
delta = max((per50_2 - per50_1), 1);
*psll50 = psll50_1 + (psll50_2 - psll50_1) *
(50 - per50_1) / delta;
}
if (*psll99 == -1) {
delta = max((per99_2 - per99_1), 1);
*psll99 = psll99_1 + (psll99_2 - psll99_1) *
(99 - per99_1) / delta;
}
}
/* function to calculate linear interpolation*/
int rampweight(int v1, int v2, int t1, int t2, int t)
{
int retval = v1;
if (t1 == t2) {
retval = (t < t1) ? (v1) : (v2);
} else {
if (t <= t1)
retval = v1;
else if (t >= t2)
retval = v2;
else
retval = v1 + (v2 - v1) * (t - t1) / (t2 - t1);
}
return retval;
}
/*p1 calculation based on default setting and*/
/*content statistic information(percentile)*/
int calcp1(int sx, int sy, int tgtL, int calcmaxl,
struct basisootf_params *basisootf_params,
int *p1_red_gain)
{
int ax, ay, k, p1_limit, k2, p1_t, p1;
int low_sy_g, high_k_g, high_tm_g, red_p1;
ax = min(sx, PORCESSING_DATA_MAX);
ay = min(sy, PORCESSING_DATA_MAX);
k = tgtL * PORCESSING_DATA_MAX / max(tgtL, calcmaxl);
p1_limit = rampweight(basisootf_params->P1_LIMIT_V2,
basisootf_params->P1_LIMIT_V1,
basisootf_params->P1_LIMIT_T1,
basisootf_params->P1_LIMIT_T2,
sy);
k2 = (PORCESSING_DATA_MAX + 1 - ax) * PORCESSING_DATA_MAX /
(ORDER * (PORCESSING_DATA_MAX + 1 - ay));
p1_t = k2 * PORCESSING_DATA_MAX / k;
p1 = max(min(p1_t, p1_limit), 0);
low_sy_g = rampweight(PORCESSING_DATA_MAX + 1, 0,
basisootf_params->LOW_SY_T1,
basisootf_params->LOW_SY_T2,
sy);
high_k_g = rampweight(PORCESSING_DATA_MAX + 1, 0,
basisootf_params->LOW_K_T1,
basisootf_params->LOW_K_T2,
k);
high_tm_g = low_sy_g * high_k_g >> PROCESSING_MAX;
red_p1 = rampweight(PORCESSING_DATA_MAX + 1,
basisootf_params->RED_P1_V1,
basisootf_params->RED_P1_T1,
basisootf_params->RED_P1_T2,
high_tm_g);
p1 = min(max((p1 * red_p1) >> PROCESSING_MAX, P1MIN), p1_limit);
if (p1_red_gain)
*p1_red_gain = high_tm_g;
return p1;
}
/*gen BasisOOTF parameters (sx,sy,p1~pn-1),based on content percentiles*/
/*and default bezier params*/
int basisootf(struct scene2094metadata *metadata,
struct basisootf_params *basisootf_params, int productpeak,
int sourcemaxl, struct ebzcurveparameters *scenebezierparams)
{
int order = ORDER;
int psll50, psll99, centerluminance, k, sy1, sy2, sy, sx, rem;
int high_tm_g, p1, rem_p29, rem_ps, rem_red_p2, ps2to9[ORDER - 1];
int coeffi, plin[ORDER - 1], pcoeff[ORDER - 1];
int targetluminance = productpeak;
int sourceluminance = max(targetluminance, sourcemaxl);
int i;
getpercentile_50_99(&metadata->percentiles, &psll50, &psll99);
centerluminance = psll50 * PORCESSING_DATA_MAX / max(psll99, 1);
k = targetluminance * PORCESSING_DATA_MAX / sourceluminance;
if (hdr10_plus_printk & 2)
pr_hdr("basisOOTF precision: ctrL=%d, k=%d\n",
centerluminance, k);
sy1 = rampweight(basisootf_params->SY1_V1,
basisootf_params->SY1_V2,
basisootf_params->SY1_T1,
basisootf_params->SY1_T2,
k);
sy2 = rampweight(basisootf_params->SY2_V1,
basisootf_params->SY2_V2,
basisootf_params->SY2_T1,
basisootf_params->SY2_T2,
k);
rem = rampweight(basisootf_params->KP_G_V1,
basisootf_params->KP_G_V2,
basisootf_params->KP_G_T1,
basisootf_params->KP_G_T2,
centerluminance);
sy = (rem * sy1 + (PORCESSING_DATA_MAX + 1 - rem) * sy2) >>
PROCESSING_MAX;
sx = sy * k;
/*P coefficient*/
high_tm_g = 0;
p1 = calcp1(sx, sy, targetluminance, sourcemaxl,
basisootf_params, &high_tm_g);
if (hdr10_plus_printk & 2)
pr_hdr("basisOOTF precision: p1=(int) %d\n\n", p1);
for (i = 0; i < (NPCOEFF - 1); i++) {
rem_p29 = rampweight(basisootf_params->P2TOP9_MAX2[i],
basisootf_params->P2TOP9_MAX1[i],
basisootf_params->P2TO9_T1,
basisootf_params->P2TO9_T2,
centerluminance);
ps2to9[i] = (rem_p29 * basisootf_params->P2TOP9_MAX1[i] +
(PORCESSING_DATA_MAX + 1 - rem_p29) *
basisootf_params->P2TOP9_MAX2[i]) >> PROCESSING_MAX;
if (hdr10_plus_printk & 2)
pr_hdr("basisOOTF precision: g=%d ps2to9[%d] = %d\n",
rem_p29, i, ps2to9[i]);
}
rem_ps = rampweight(PORCESSING_DATA_MAX + 1, 0,
basisootf_params->PS_G_T1,
basisootf_params->PS_G_T2, k);
pcoeff[0] = p1;
for (i = 1; i < NPCOEFF; i++) {
coeffi = i + 1;
plin[i] = (coeffi * PORCESSING_DATA_MAX / order);
pcoeff[i] = max(min((rem_ps * ps2to9[i - 1] +
(PORCESSING_DATA_MAX + 1 - rem_ps) * plin[i])
>> PROCESSING_MAX,
coeffi * p1),
plin[i]);
if (hdr10_plus_printk & 2)
pr_hdr("basisOOTF precision: g=%d, pcoeff[%d] = %d\n",
rem_ps, i, pcoeff[i]);
}
/*p[1] recalc precision:0.01,bad*/
rem_red_p2 = rampweight(PORCESSING_DATA_MAX + 1,
basisootf_params->RED_P2_V1,
basisootf_params->RED_P2_T1,
basisootf_params->RED_P2_T2,
high_tm_g);
pcoeff[1] = max(min((pcoeff[1] * rem_red_p2) >> PROCESSING_MAX, 2 * p1),
2 * PORCESSING_DATA_MAX / ORDER);
/*finally pcoeff[ORDER-1],sy,sx*/
scenebezierparams->sx = sx;
scenebezierparams->sy = sy;
/*only calc ORDER(10) < actual order(15)*/
for (i = 0; i < NPCOEFF; i++)
scenebezierparams->anchor[i] = pcoeff[i];
if (hdr10_plus_printk & 2) {
pr_hdr("default P setting:\n");
for (i = 0; i < NPCOEFF; i++)
pr_hdr("%2d: %d\n", i, pcoeff[i]);
}
return 0;
}
/* receive bezier parameter(Kx,ky,P)and return guided parameter base on*/
/*product panel luminance out: product curve params(Kx,ky,P) */
int guidedootf(struct scene2094metadata *metadata,
struct basisootf_params *basisootf_params,
struct ebzcurveparameters *referencebezierparams,
int productpeak,
struct ebzcurveparameters *productbezierparams)
{
int KP_BYPASS = 1229;
int refenceluminance = metadata->referenceluminance;
int productluminance = productpeak;
int minluminance = metadata->minluminance;
int maxluminance = metadata->maxscenesourceluminance;
int order = referencebezierparams->order;
int nump = order - 1;
int blendcoeff, norm;
int anchorlinear[N];
int i;
int ps1;
struct ebzcurveparameters minbezierparams;
ebzcurveparametersinit(&minbezierparams);
for (i = 0; i < nump; i++)
anchorlinear[i] = (i + 1) * PORCESSING_DATA_MAX / order;
if (hdr10_plus_printk & 2) {
pr_hdr("order = %d, linear ps[i]:\n",
order);
for (i = 0; i < nump; i++)
pr_hdr(" %2d: %4d\n",
i, anchorlinear[i]);
}
/*patch for low luminance panel tm calculate, find rootcause next step*/
if (force_ref_peak) {
refenceluminance = force_ref_peak;
if (refenceluminance < 250)
refenceluminance = 0;
}
/*---------case 0: productPeak < minL ----------------- */
if (productluminance < minluminance) {
if (hdr10_plus_printk & 2) {
pr_hdr("case: P < minL\n\n...processing...\n");
pr_hdr("error GuidedOOTF: < %d nit not supported\n",
productluminance);
}
productbezierparams->sx = 0;
productbezierparams->sy = 0;
for (i = 0; i < nump; i++)
productbezierparams->anchor[i] = anchorlinear[i];
productbezierparams->order = order;
return -1;
}
/*---------case 1: productPeak = ref ----------------- */
if (productluminance == refenceluminance) {
if (hdr10_plus_printk & 2)
pr_hdr("case: P = ref\n\n...processing...\n");
productbezierparams->sx = referencebezierparams->sx;
productbezierparams->sy = referencebezierparams->sy;
productbezierparams->order = referencebezierparams->order;
for (i = 0; i < nump; i++)
productbezierparams->anchor[i] =
referencebezierparams->anchor[i];
if (hdr10_plus_printk & 2) {
pr_hdr("order:%2d, (sx,sy):(%4d, %4d)\n",
productbezierparams->order,
productbezierparams->sx,
productbezierparams->sy);
for (i = 0; i < nump; i++)
pr_hdr(" %2d: %4d\n",
i, productbezierparams->anchor[i]);
}
/*---------case 2: productPeak > maxL ----------------- */
} else if (productluminance > maxluminance) {
if (hdr10_plus_printk & 2)
pr_hdr("case: P > maxL\n\n...processing...\n");
productbezierparams->sx = KP_BYPASS;
productbezierparams->sy = KP_BYPASS;
productbezierparams->order = order;
for (i = 0; i < nump; i++)
productbezierparams->anchor[i] = anchorlinear[i];
/*---------case 3: minL < productPeak < maxL ----------------- */
} else {
productbezierparams->order = referencebezierparams->order;
/*---------case 3.1: minL < productPeak < ref ----------------- */
if (productluminance < refenceluminance) {
if (hdr10_plus_printk & 2)
pr_hdr("case: P < ref\n\n...processing...\n");
norm = refenceluminance - minluminance;
blendcoeff = refenceluminance - productluminance;
basisootf(metadata, basisootf_params, minluminance,
maxluminance, &minbezierparams);
productbezierparams->sy =
(blendcoeff * minbezierparams.sy +
(norm - blendcoeff) * referencebezierparams->sy +
(norm >> 1)) / norm;
productbezierparams->sx =
productbezierparams->sy * productluminance /
maxluminance;
for (i = 0; i < nump ; i++) {
productbezierparams->anchor[i] =
(blendcoeff * minbezierparams.anchor[i] +
(norm - blendcoeff) *
referencebezierparams->anchor[i] +
(norm >> 1)) / norm;
}
if (hdr10_plus_printk & 2) {
pr_hdr("p-1=>Anchor[i] = ");
pr_hdr("(blendcoeff *referenceBezierParams->Anchor[i] ");
pr_hdr("+ (norm - blendcoeff)*minBezierParams.Anchor[i]");
pr_hdr(" + (norm>>1) )/norm\n");
for (i = 0; i < nump; i++) {
pr_hdr("p-1=> %2d: %4d = ",
i,
productbezierparams->anchor[i]);
pr_hdr(" %4d * %4d + ",
blendcoeff,
referencebezierparams->anchor[i]);
pr_hdr("(%4d - %4d) * %4d / %4d\n",
norm,
blendcoeff,
minbezierparams.anchor[i],
norm);
}
}
/*---------case 3.2: ref < productPeak < maxL ----------------- */
} else {
if (hdr10_plus_printk & 2)
pr_hdr("case: P > ref\n\n...processing...\n");
norm = maxluminance - refenceluminance;
blendcoeff = productluminance - refenceluminance;
productbezierparams->sy = (blendcoeff * KP_BYPASS +
(norm - blendcoeff) * referencebezierparams->sy +
(norm >> 1)) / norm;
productbezierparams->sx = productbezierparams->sy *
productluminance / maxluminance;
for (i = 0; i < nump; i++) {
productbezierparams->anchor[i] =
(blendcoeff * anchorlinear[i] +
(norm - blendcoeff) *
referencebezierparams->anchor[i] +
(norm >> 1)) / norm;
}
if (hdr10_plus_printk & 2) {
for (i = 0; i < nump; i++) {
pr_hdr("p-1=> %2d: %4d = ",
i,
productbezierparams->anchor[i]);
pr_hdr(" %4d * %4d + ",
blendcoeff,
anchorlinear[i]);
pr_hdr("(%4d - %4d) * %4d / %4d\n",
norm,
blendcoeff,
referencebezierparams->anchor[i],
norm);
}
}
}
ps1 = calcp1(productbezierparams->sx,
productbezierparams->sy,
productluminance, maxluminance,
basisootf_params, NULL);
productbezierparams->anchor[0] = ps1;
for (i = 1; i < nump; i++) {
productbezierparams->anchor[i] =
min(productbezierparams->anchor[i],
(i + 1) * productbezierparams->anchor[0]);
}
if (hdr10_plus_printk & 2) {
pr_hdr("p-2: %2d, %4d\n", 0, ps1);
// p process, form curve below CI line slope
for (i = 1; i < nump; i++)
pr_hdr("p-2=> %2d-> %d\n",
i, productbezierparams->anchor[i]);
}
}
return 0;
}
/*bezier optimise method to gen bezier function*/
int decasteliau(u64 *beziercurve, u64 *anchory,
u64 u, int order, u64 range_ebz_x)
{
u64 pointy[N + 2];
int i, j;
for (i = 0; i < order + 1; i++)
pointy[i] = anchory[i];
for (i = 1; i <= order; i++)
for (j = 0; j <= order - i; j++) {
pointy[j] = (pointy[j] * (range_ebz_x - u) +
pointy[j + 1] * u + range_ebz_x / 2);
pointy[j] = div64_u64(pointy[j], range_ebz_x);
}
beziercurve[1] = pointy[0];
return 0;
}
#define org_anchory
u64 oo_lut_x[OOLUT_NUM] = {
1, 16, 32, 64, 128, 256, 512, 1024, 2048, 2560, 3072, 3584, 4096,
5120, 6144, 7168, 8192, 10240, 12288, 14336, 16384, 20480, 24576,
28672, 32768, 40960, 49152, 57344, 65536, 81920, 98304, 114688,
131072, 163840, 196608, 229376, 262144, 327680, 393216, 458752,
524288, 655360, 786432, 917504, 1048576, 1179648, 1310720, 1441792,
1572864, 1703936, 1835008, 1966080, 2097152, 2359296, 2621440, 2883584,
3145728, 3407872, 3670016, 3932160, 4194304, 4718592, 5242880, 5767168,
6291456, 6815744, 7340032, 7864320, 8388608, 9437184, 10485760,
11534336, 12582912, 13631488, 14680064, 15728640, 16777216, 18874368,
20971520, 23068672, 25165824, 27262976, 29360128, 31457280, 33554432,
37748736, 41943040, 46137344, 50331648, 54525952, 58720256, 62914560,
67108864, 75497472, 83886080, 92274688, 100663296, 109051904, 117440512,
125829120, 134217728, 150994944, 167772160, 184549376, 201326592,
218103808, 234881024, 251658240, 268435456, 301989888, 335544320,
369098752, 402653184, 436207616, 469762048, 503316480, 536870912,
603979776, 671088640, 738197504, 805306368, 872415232, 939524096,
1006632960, 1073741824, 1207959552, 1342177280, 1476395008, 1610612736,
1744830464, 1879048192, 2013265920ULL, 2147483648ULL, 2281701376ULL,
2415919104ULL, 2550136832ULL, 2684354560ULL, 2818572288ULL,
2952790016ULL, 3087007744ULL, 3221225472ULL, 3355443200ULL,
3489660928ULL, 3623878656ULL, 3758096384ULL,
3892314112ULL, 4026531840ULL, 4160749568ULL, 4294967296ULL
};
/*gen OOTF curve and gain from (sx,sy) and P1~pn-1*/
int gen_ebzurve(u64 *curvex, u64 *curvey,
unsigned int *gain,
u64 nkx, uint64_t nky,
u64 *anchory, int order)
{
u64 my_anchor_y[N + 2];
u64 temp;
u64 kx, ky;
u64 range_ebz_x;
u64 range_ebz_y;
u64 step_alpha;
u64 beziercurve[2];
int i;
int nump;
if (order > 1 && order <= N + 1)
nump = order - 1;
else
nump = N - 1;
/*u12->U16*/
kx = nkx << (U32 - PROCESSING_MAX);
ky = nky << (U32 - PROCESSING_MAX);
range_ebz_x = _U32_MAX - kx;
range_ebz_y = _U32_MAX - ky;
#ifdef org_anchory
for (i = 0; i < nump; i++)/* u12-> ebz_y, u32*/
/*anchorY default range:PROCESSING_MAX */
my_anchor_y[i + 1] = anchory[i] << (U32 - PROCESSING_MAX);
my_anchor_y[0] = 0;
my_anchor_y[nump + 1] = _U32_MAX; /* u12 */
#else
for (i = 0; i < nump; i++)/* u12-> ebz_y, u32*/
/*anchorY default range:PROCESSING_MAX */
my_anchor_y[i + 1] =
(anchory[i] * range_ebz_y) >> PROCESSING_MAX;
my_anchor_y[0] = 0;
my_anchor_y[N] = range_ebz_y; /*u12 -> U32*/
#endif /* org_anchory */
for (i = 0; i < POINTS; i++)
curvey[i] = 0;
for (i = 0; i < POINTS; i++) {
if (oo_lut_x[i] < kx) {
curvex[i] = oo_lut_x[i];/*u32*/
curvey[i] = oo_lut_x[i] * ky;
curvey[i] = div64_u64(curvey[i], kx ? kx : 1);
temp = curvey[i] << GAIN_BIT;/*u12*/
gain[i] = div64_u64(temp, oo_lut_x[i]);
} else {
/*norm in Decasteliau() function*/
step_alpha = (oo_lut_x[i] - kx);
/* calc each point from 1st to N-th layer*/
decasteliau(&beziercurve[0], my_anchor_y, step_alpha,
order, range_ebz_x);
#ifdef org_anchory /*range_ebz_y = _U32_MAX*/
curvey[i] = ky +
((range_ebz_y * beziercurve[1] + range_ebz_y / 2)
>> U32);
#else
curvey[i] = ky + ((range_ebz_y * beziercurve[1] +
range_ebz_y / 2));
curvey[i] = div64_u64(curvey[i], range_ebz_y);
#endif /* org_anchory*/
/*CurveX[i] = Kx +*/
/*((range_ebz_x * BezierCurve[0] + range_ebz_x / 2) / */
/*range_ebz_x);*/
curvex[i] = kx + step_alpha;
temp = curvey[i] << GAIN_BIT;
gain[i] = div64_u64(temp, oo_lut_x[i]);
if (gain[i] < (1 << GAIN_BIT))
gain[i] = 1 << GAIN_BIT;
}
}
gain[POINTS - 1] = 1 << GAIN_BIT;
return 0;
}
void vframe_hdr_plus_sei_s_init(struct hdr10_plus_sei_s *hdr10_plus_sei)
{
struct hdr10_plus_sei_s *p;
struct vframe_hdr_plus_sei *pvf;
int i;
int P_init[N - 1] = {181, 406, 607, 796, 834, 863, 890, 917, 938};
int percentilepercent_init[PERCENTILE_ORDER] = {
1, 5, 10, 25, 50, 75, 90, 95, 99};
/*int percentilevalue_init[PERCENTILE_ORDER] = {*/
/* 0, 1, 2, 79, 2537, 9900, 9901, 9902, 9904};*/
p = hdr10_plus_sei;
pvf = &hdr_plus_sei;
hdr10_plus_sei->num_distributions[0] = PERCENTILE_ORDER - 1;
for (i = 0; i < 3; i++)
hdr10_plus_sei->maxscl[0][i] = hdr_plus_sei.maxscl[0][i];
hdr10_plus_sei->targeted_system_display_maximum_luminance =
hdr_plus_sei.tgt_sys_disp_max_lumi;
/*for hdmitx output no number, default 9*/
if (hdr10_plus_sei->num_distributions[0] == 0)
hdr10_plus_sei->num_distributions[0] = 9;
for (i = 0; i < (hdr10_plus_sei->num_distributions[0]); i++) {
hdr10_plus_sei->distribution_index[0][i] =
hdr_plus_sei.distribution_maxrgb_percentages[0][i];
/*hdmitx have no distribution index, default init*/
if (hdr10_plus_sei->distribution_index[0][i] == 0)
hdr10_plus_sei->distribution_index[0][i] =
percentilepercent_init[i];
hdr10_plus_sei->distribution_values[0][i] =
hdr_plus_sei.distribution_maxrgb_percentiles[0][i];
}
hdr10_plus_sei->knee_point_x[0] = hdr_plus_sei.knee_point_x[0];
hdr10_plus_sei->knee_point_y[0] = hdr_plus_sei.knee_point_y[0];
if (hdr_plus_sei.num_bezier_curve_anchors[0]) {
hdr10_plus_sei->num_bezier_curve_anchors[0] =
hdr_plus_sei.num_bezier_curve_anchors[0];
for (i = 0;
i < (hdr10_plus_sei->num_bezier_curve_anchors[0]);
i++)
hdr10_plus_sei->bezier_curve_anchors[0][i] =
hdr_plus_sei.bezier_curve_anchors[0][i] <<
(PROCESSING_MAX - 10);
} else {
hdr10_plus_sei->num_bezier_curve_anchors[0] = 9;
for (i = 0; i < 9; i++)
hdr10_plus_sei->bezier_curve_anchors[0][i] =
P_init[i] << (PROCESSING_MAX - 10);
}
/*debug--*/
if (hdr10_plus_printk & 1) {
for (i = 0; i < 3; i++)
pr_hdr("hdr10_plus_sei->maxscl[0][%d]=%d\n",
i, hdr10_plus_sei->maxscl[0][i]);
pr_hdr("targeted_system_display_maximum_luminance=%d\n",
p->targeted_system_display_maximum_luminance);
for (i = 0; i < (hdr10_plus_sei->num_distributions[0]); i++) {
pr_hdr("distribution_values[0][%d]=%d\n",
i, hdr10_plus_sei->distribution_values[0][i]);
pr_hdr("hdr10_plus_sei->distribution_index[0][%d]=%d\n",
i, hdr10_plus_sei->distribution_index[0][i]);
}
pr_hdr("hdr10_plus_sei->knee_point_x = %d\n"
"hdr10_plus_sei->knee_point_y = %d\n",
hdr10_plus_sei->knee_point_x[0],
hdr10_plus_sei->knee_point_y[0]);
pr_hdr("hdr10_plus_sei->num_bezier_curve_anchors[0] = %d\n",
hdr_plus_sei.num_bezier_curve_anchors[0]);
for (i = 0; i < (hdr10_plus_sei->num_bezier_curve_anchors[0]);
i++) {
pr_hdr("bezier_curve_anchors[0][%d] = %d\n",
i, hdr_plus_sei.bezier_curve_anchors[0][i]);
}
for (i = 0; i < 3; i++) {
pr_hdr("average_maxrgb[%d] = %d\n",
i, hdr_plus_sei.average_maxrgb[i]);
}
for (i = 0;
i < (pvf->num_distribution_maxrgb_percentiles[0]);
i++) {
pr_hdr("distribution_maxrgb_percentages[0][%d] = %d\n",
i, pvf->distribution_maxrgb_percentages[0][i]);
}
for (i = 0;
i < (pvf->num_distribution_maxrgb_percentiles[0]);
i++) {
pr_hdr("distribution_maxrgb_percentiles[0][%d] = %d\n",
i, pvf->distribution_maxrgb_percentiles[0][i]);
}
}
}
void vframe_hdr_sei_s_init(struct hdr10_plus_sei_s *hdr10_plus_sei,
int source_lumin)
{
int i;
int P_init[N - 1] = {181, 406, 607, 796, 834, 863, 890, 917, 938};
int percentilepercent_init[PERCENTILE_ORDER] = {
1, 5, 10, 25, 50, 75, 90, 95, 99
};
int percentilevalue_init[PERCENTILE_ORDER] = {
0, 10000, 90, 2000, 4000, 8000, 10000, 10001, 10002
};
for (i = 0; i < 9; i++)
percentilevalue_init[i] = percentile[i];
if (hdr10_plus_printk & 8) {
for (i = 0; i < 9; i++) {
pr_hdr("percentilevalue_init[%d] = %d\n",
i, percentilevalue_init[i]);
}
}
hdr10_plus_sei->num_distributions[0] = PERCENTILE_ORDER - 1;
for (i = 0; i < 3; i++)
hdr10_plus_sei->maxscl[0][i] = percentilevalue_init[8] * 10;
hdr10_plus_sei->targeted_system_display_maximum_luminance = 0;
hdr10_plus_sei->num_distributions[0] = 9;
for (i = 0; i < (hdr10_plus_sei->num_distributions[0]); i++) {
hdr10_plus_sei->distribution_index[0][i] =
percentilepercent_init[i];
hdr10_plus_sei->distribution_values[0][i] =
percentilevalue_init[i];
}
hdr10_plus_sei->knee_point_x[0] = 0;
hdr10_plus_sei->knee_point_y[0] = 0;
hdr10_plus_sei->num_bezier_curve_anchors[0] = 9;
for (i = 0; i < 9; i++)
hdr10_plus_sei->bezier_curve_anchors[0][i] =
P_init[i] << (PROCESSING_MAX - 10);
for (i = 0; i < 3; i++)
hdr_plus_sei.average_maxrgb[i] = percentilevalue_init[8];
hdr_plus_sei.num_distribution_maxrgb_percentiles[0] = 0;
}
unsigned int gain[POINTS];
u64 curvex[POINTS], curvey[POINTS];
/*input o->10000, should adaptive scale by shift and gamut*/
static int match_ootf_output(struct scene2094metadata *metadata,
struct hdr10pgen_param_s *p_hdr10pgen_param,
int panel_lumin)
{
unsigned int scale_float;
unsigned int maxl;
maxl = metadata->maxscenesourceluminance;
if (!maxl)
maxl = 1000;
if (maxl < panel_lumin)
maxl = panel_lumin;
/*o->10000 scale*/
scale_float = 10000 * 1024 / maxl;
p_hdr10pgen_param->shift = _log2(scale_float) - 10;
/* right shifting by more than 31 bits has undefined behavior. */
if (p_hdr10pgen_param->shift < 32)
p_hdr10pgen_param->scale_gmt =
scale_float >> p_hdr10pgen_param->shift;
memcpy(p_hdr10pgen_param->gain, gain, sizeof(unsigned int) * POINTS);
if (hdr10_plus_printk & 4) {
pr_hdr("maxl=%d, scale=%d, shift=%d, ",
maxl, scale_float,
p_hdr10pgen_param->shift);
pr_hdr("scale_gmt=%d, gain=%d-%d-%d\n",
p_hdr10pgen_param->scale_gmt,
gain[0], gain[86], gain[148]);
}
return 0;
}
// //mapping
// struct hdr_proc_lut_param_s _hdr_lut_param;
int hdr10_plus_ootf_gen(int panel_lumin,
int force_source_lumin,
struct hdr10pgen_param_s *p_hdr10pgen_param)
{
/*int referenceCurve_flag = 1;*/
int order, i;
u64 kx, ky;
u64 anchory[N];
/* bezier params obtained from metadata */
static struct hdr10_plus_sei_s hdr10_plus_sei;
static struct scene2094metadata metadata;
static struct ebzcurveparameters referencebezierparams;
static struct ebzcurveparameters productbezierparams;
static struct basisootf_params basisootf_params;
int productpeak = panel_lumin;
memset(curvex, 0, sizeof(uint64_t) * POINTS);
memset(curvey, 0, sizeof(uint64_t) * POINTS);
memset(gain, 0, sizeof(unsigned int) * POINTS);
basisootf_params_init(&basisootf_params);
/* the final tv OOTF curve params init*/
ebzcurveparametersinit(&productbezierparams);
/* the bezier parameters from metadata init*/
ebzcurveparametersinit(&referencebezierparams);
/* repace with real vframe data*/
if (!force_source_lumin)
vframe_hdr_plus_sei_s_init(&hdr10_plus_sei);
else
vframe_hdr_sei_s_init(&hdr10_plus_sei, force_source_lumin);
/*step 1. get metadata from vframe*/
metadatainit(&metadata, &hdr10_plus_sei);
/*step 2. get bezier params from metadata*/
getmetadata(&metadata, &referencebezierparams);
/*step 3. gen final guided OOTF*/
/*if (referenceCurve_flag == 0)*/
/* Basis OOTF : Direct calculation of product TM curve from*/
/*ST-2094 percentile metadata */
/*basisOOTF(&metadata, &basisOOTF_Params, productPeak,*/
/* here length(minBezierParams->Anchor) =order*/
/*metadata.maxscenesourceluminance, &productBezierParams);*/
/*else*/
guidedootf(&metadata, &basisootf_params,
&referencebezierparams, productpeak,
&productbezierparams);
if (hdr10_plus_printk & 2) {
pr_hdr("productPeak=%d\n", panel_lumin);
pr_hdr("\n===================guided out ===================\n");
pr_hdr("1. knee point : (%4d,%4d)\n",
productbezierparams.sx, productbezierparams.sy);
pr_hdr("2. Bezier order : %d\n",
referencebezierparams.order);
pr_hdr("3. Bezier P coeffs :\n");
for (i = 0; i < (productbezierparams.order - 1); i++)
pr_hdr(" %2d: %4d\n",
i, productbezierparams.anchor[i]);
pr_hdr("\n=================================================\n");
}
/*step 4. get guided bezier params*/
kx = (uint64_t)productbezierparams.sx;
ky = (uint64_t)productbezierparams.sy;
order = productbezierparams.order;
for (i = 0; i < productbezierparams.order - 1; i++)
anchory[i] = (uint64_t)productbezierparams.anchor[i];
/*step 5. gen bezier curve*/
gen_ebzurve(&curvex[0], &curvey[0], &gain[0],
kx, ky, &anchory[0], order);
/* debug */
if (hdr10_plus_printk & 8) {
for (i = 0; i < POINTS; i++) {
pr_hdr("fixed : %3d:(%lld, %lld)->%4d\n",
i, curvex[i], curvey[i], gain[i]);
}
}
match_ootf_output(&metadata, p_hdr10pgen_param, panel_lumin);
hdr10_plus_printk = 0;
return 0;
}