amd/gmlib: add gmlib for radeonsi

radeonsi drivers can use gmlib to generate 3dlut used to do tonemapping.

Signed-off-by: Peyton Lee <peytolee@amd.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/33731>
This commit is contained in:
Peyton Lee 2025-02-25 16:51:21 +08:00 committed by Marge Bot
parent 2e124dd389
commit 2e46c41448
27 changed files with 6471 additions and 0 deletions

1
src/amd/gmlib/README.md Executable file
View file

@ -0,0 +1 @@
# GMLib

View file

@ -0,0 +1,45 @@
/* Copyright 2025 Advanced Micro Devices, Inc.
* SPDX-License-Identifier: MIT
*
* Authors: AMD
*
*/
#pragma once
#include "ToneMapTypes.h"
#include "AGMGenerator.h"
struct SrcTmParams {
struct ToneMapHdrMetaData streamMetaData;
enum ToneMapTransferFunction inputContainerGamma;
};
struct DstTmParams {
struct ToneMapHdrMetaData dstMetaData;
enum ToneMapTransferFunction outputContainerGamma;
enum ToneMapColorPrimaries outputContainerPrimaries;
};
struct ToneMapGenerator {
struct AGMGenerator agmGenerator;
enum ToneMapAlgorithm tmAlgo;
bool memAllocSet;
struct SrcTmParams cachedSrcTmParams;
struct DstTmParams cachedDstTmParams;
};
enum TMGReturnCode ToneMapGenerator_GenerateToneMappingParameters(
struct ToneMapGenerator* p_tmGenerator,
const struct ToneMapHdrMetaData* streamMetaData,
const struct ToneMapHdrMetaData* dstMetaData,
enum ToneMapTransferFunction inputContainerGamma,
enum ToneMapTransferFunction outputContainerGamma,
enum ToneMapColorPrimaries outputContainerPrimaries,
unsigned short lutDim,
struct ToneMappingParameters* tmParams);
enum TMGReturnCode ToneMapGenerator_SetInternalAllocators(
struct ToneMapGenerator* p_tmGenerator,
TMGAlloc allocFunc,
TMGFree freeFunc,
void* memCtx);

View file

@ -0,0 +1,73 @@
/* Copyright 2025 Advanced Micro Devices, Inc.
* SPDX-License-Identifier: MIT
*
* Authors: AMD
*
*/
#pragma once
#include <stdbool.h>
#define MAX_LUMINANCE 10000.0
#define INPUT_NORMALIZATION_FACTOR 4000 //nits
typedef void* (*TMGAlloc)(unsigned int, void*);
typedef void (*TMGFree)(void*, void*);
struct ToneMapHdrMetaData
{
unsigned short redPrimaryX;
unsigned short redPrimaryY;
unsigned short greenPrimaryX;
unsigned short greenPrimaryY;
unsigned short bluePrimaryX;
unsigned short bluePrimaryY;
unsigned short whitePointX;
unsigned short whitePointY;
unsigned int maxMasteringLuminance;
unsigned int minMasteringLuminance;
unsigned short maxContentLightLevel;
unsigned short maxFrameAverageLightLevel;
};
enum ToneMapTransferFunction {
TMG_TF_SRGB,
TMG_TF_BT709,
TMG_TF_G24,
TMG_TF_PQ,
TMG_TF_NormalizedPQ,
TMG_TF_ModifiedPQ,
TMG_TF_Linear,
TMG_TF_HLG
};
enum ToneMapColorPrimaries {
TMG_CP_BT601,
TMG_CP_BT709,
TMG_CP_BT2020,
TMG_CP_DCIP3
};
enum ToneMapAlgorithm {
TMG_A_AGM,
TMG_A_BT2390,
TMG_A_BT2390_4
};
struct ToneMappingParameters {
enum ToneMapColorPrimaries lutColorIn;
enum ToneMapColorPrimaries lutColorOut;
enum ToneMapTransferFunction shaperTf;
enum ToneMapTransferFunction lutOutTf;
unsigned short lutDim;
unsigned short* lutData;
void* formattedLutData;
unsigned short inputNormalizationFactor;
};
enum TMGReturnCode {
TMG_RET_OK,
TMG_RET_ERROR_DUPLICATE_INIT,
TMG_RET_ERROR_INVALID_PARAM,
TMG_RET_ERROR_NOT_INITIALIZED,
TMG_RET_ERROR_GMLIB
};

View file

@ -0,0 +1,39 @@
/* Copyright 2025 Advanced Micro Devices, Inc.
* SPDX-License-Identifier: MIT
*
* Authors: AMD
*
*/
#pragma once
#include "ToneMapTypes.h"
#include "gm_api_funcs.h"
/* Replace CPP class: AGMGenerator */
struct AGMGenerator {
TMGAlloc allocFunc;
TMGFree freeFunc;
void* memoryContext;
bool initalized;
struct s_gamut_map agmParams;
struct s_gm_opts gamutMapParams;
};
enum TMGReturnCode AGMGenerator_ApplyToneMap(
struct AGMGenerator* p_agm_generator,
const struct ToneMapHdrMetaData* streamMetaData,
const struct ToneMapHdrMetaData* dtMetaData,
const enum ToneMapAlgorithm tmAlgorithm,
const struct ToneMappingParameters* tmParams,
bool updateSrcParams,
bool updateDstParams,
bool enableMerge3DLUT);
enum TMGReturnCode AGMGenerator_SetGMAllocator(
struct AGMGenerator* p_agm_generator,
TMGAlloc allocFunc,
TMGFree freeFunc,
void* memCtx);
/* Replace ~AGMGenerator() */
void AGMGenerator_Exit(struct AGMGenerator* p_agm_generator);

View file

@ -0,0 +1,176 @@
/* Copyright 2025 Advanced Micro Devices, Inc.
* SPDX-License-Identifier: MIT
*
* Authors: AMD
*
*/
#pragma once
#include "csc_api_funcs.h"
#include "ToneMapTypes.h"
static bool TranslateTfEnum(
enum ToneMapTransferFunction inTf,
enum cs_gamma_type* outTf)
{
switch (inTf) {
case(TMG_TF_SRGB):
*outTf = EGT_sRGB;
break;
case(TMG_TF_BT709):
*outTf = EGT_709;
break;
case(TMG_TF_G24):
*outTf = EGT_2_4;
break;
case(TMG_TF_HLG):
*outTf = EGT_HLG;
break;
case(TMG_TF_NormalizedPQ):
case(TMG_TF_PQ):
*outTf = EGT_PQ;
break;
default:
return false;
}
return true;
}
static void CSCCtor(struct s_csc_map* csc_map)
{
csc_ctor(csc_map);
}
static enum TMGReturnCode CSCSetOptions(
const struct ToneMapHdrMetaData* srcMetaData,
enum ToneMapTransferFunction inTf,
const struct ToneMapHdrMetaData* dstMetaData,
enum ToneMapTransferFunction outTf,
const struct ToneMappingParameters* tmParams,
bool merge3DLUT,
struct s_csc_api_opts* csc_opts)
{
enum TMGReturnCode ret = TMG_RET_OK;
enum cs_gamma_type inGamma;
enum cs_gamma_type outGamma;
if (!TranslateTfEnum(inTf, &inGamma)) {
ret = TMG_RET_ERROR_INVALID_PARAM;
goto exit;
}
if(!TranslateTfEnum(outTf, &outGamma)) {
ret = TMG_RET_ERROR_INVALID_PARAM;
goto exit;
}
csc_opts->ptr_3dlut_rgb = tmParams->lutData;
csc_opts->num_pnts_3dlut = tmParams->lutDim;
csc_opts->bitwidth_3dlut = 12;
csc_opts->en_merge_3dlut = merge3DLUT;
csc_opts->cs_opts_src.color_space_type = ECST_CUSTOM;
csc_opts->cs_opts_src.rgbw_xy[0] =
srcMetaData->redPrimaryX / 50000.0;
csc_opts->cs_opts_src.rgbw_xy[1] =
srcMetaData->redPrimaryY / 50000.0;
csc_opts->cs_opts_src.rgbw_xy[2] =
srcMetaData->greenPrimaryX / 50000.0;
csc_opts->cs_opts_src.rgbw_xy[3] =
srcMetaData->greenPrimaryY / 50000.0;
csc_opts->cs_opts_src.rgbw_xy[4] =
srcMetaData->bluePrimaryX / 50000.0;
csc_opts->cs_opts_src.rgbw_xy[5] =
srcMetaData->bluePrimaryY / 50000.0;
csc_opts->cs_opts_src.rgbw_xy[6] =
srcMetaData->whitePointX / 50000.0;
csc_opts->cs_opts_src.rgbw_xy[7] =
srcMetaData->whitePointY / 50000.0;
csc_opts->cs_opts_src.gamma_type = inGamma;
csc_opts->cs_opts_src.luminance_limits[0] = 0.0;
csc_opts->cs_opts_src.luminance_limits[1] =
(double)srcMetaData->maxMasteringLuminance;
if (inTf == TMG_TF_NormalizedPQ)
csc_opts->cs_opts_src.pq_norm = (double)tmParams->inputNormalizationFactor;
else
csc_opts->cs_opts_src.pq_norm = MAX_LUMINANCE;
csc_opts->cs_opts_dst.color_space_type = ECST_CUSTOM;
csc_opts->cs_opts_dst.rgbw_xy[0] =
dstMetaData->redPrimaryX / 50000.0;
csc_opts->cs_opts_dst.rgbw_xy[1] =
dstMetaData->redPrimaryY / 50000.0;
csc_opts->cs_opts_dst.rgbw_xy[2] =
dstMetaData->greenPrimaryX / 50000.0;
csc_opts->cs_opts_dst.rgbw_xy[3] =
dstMetaData->greenPrimaryY / 50000.0;
csc_opts->cs_opts_dst.rgbw_xy[4] =
dstMetaData->bluePrimaryX / 50000.0;
csc_opts->cs_opts_dst.rgbw_xy[5] =
dstMetaData->bluePrimaryY / 50000.0;
csc_opts->cs_opts_dst.rgbw_xy[6] =
dstMetaData->whitePointX / 50000.0;
csc_opts->cs_opts_dst.rgbw_xy[7] =
dstMetaData->whitePointY / 50000.0;
csc_opts->cs_opts_dst.gamma_type = outGamma;
csc_opts->cs_opts_dst.luminance_limits[0] = 0.0;
csc_opts->cs_opts_dst.luminance_limits[1] =
(double)dstMetaData->maxMasteringLuminance;
if (outTf == TMG_TF_NormalizedPQ)
csc_opts->cs_opts_dst.pq_norm = (double)tmParams->inputNormalizationFactor;
else
csc_opts->cs_opts_dst.pq_norm = MAX_LUMINANCE;
exit:
return ret;
}
static void CSCSetDefault(struct s_csc_api_opts* csc_opts)
{
csc_api_set_def(csc_opts);
}
static void CSCGenerateMap(struct s_csc_api_opts* csc_opts, struct s_csc_map* csc_map)
{
csc_api_gen_map(csc_opts, csc_map);
}
static enum TMGReturnCode CSCGenerate3DLUT(struct s_csc_api_opts* csc_opts, struct s_csc_map* csc_map)
{
int retcode = csc_api_gen_3dlut(csc_opts, csc_map);
return retcode ? TMG_RET_ERROR_GMLIB : TMG_RET_OK;
}
static enum TMGReturnCode CSCGenerator_ApplyCSC(
const struct ToneMapHdrMetaData* srcMetaData,
enum ToneMapTransferFunction inTf,
const struct ToneMapHdrMetaData* dstMetaData,
enum ToneMapTransferFunction outTf,
struct ToneMappingParameters* tmParams,
bool enable3DLUTMerge)
{
struct s_csc_map csc_map;
struct s_csc_api_opts csc_opts;
CSCCtor(&csc_map);
CSCSetDefault(&csc_opts);
CSCSetOptions(srcMetaData,
inTf,
dstMetaData,
outTf,
tmParams,
enable3DLUTMerge,
&csc_opts);
CSCGenerateMap(&csc_opts, &csc_map);
return CSCGenerate3DLUT(&csc_opts, &csc_map);
}

View file

@ -0,0 +1,261 @@
/* Copyright 2025 Advanced Micro Devices, Inc.
* SPDX-License-Identifier: MIT
*
* Authors: AMD
*
*/
#include "AGMGenerator.h"
// Function declaration
void AGMGenerator_GMCtor(struct AGMGenerator* p_agm_generator);
void AGMGenerator_GMSetDefault(struct AGMGenerator* p_agm_generator);
enum TMGReturnCode AGMGenerator_SetAgmOptions(
struct AGMGenerator* p_agm_generator,
const struct ToneMapHdrMetaData* srcMetaData,
const struct ToneMapHdrMetaData* dstMetaData,
const enum ToneMapAlgorithm tmAlgorithm,
const struct ToneMappingParameters* tmParams,
bool updateSrcParams,
bool updateDstParams,
bool enableMerge3DLUT);
enum TMGReturnCode AGMGenerator_GMGenerateMap(struct AGMGenerator* p_agm_generator);
enum TMGReturnCode AGMGenerator_GMGenerate3DLUT(struct AGMGenerator* p_agm_generator);
static bool TranslateTfEnum(
enum ToneMapTransferFunction inTf,
enum cs_gamma_type* outTf)
{
switch (inTf) {
case(TMG_TF_SRGB):
*outTf = EGT_sRGB;
break;
case(TMG_TF_BT709):
*outTf = EGT_709;
break;
case(TMG_TF_G24):
*outTf = EGT_2_4;
break;
case(TMG_TF_HLG):
*outTf = EGT_HLG;
break;
case(TMG_TF_NormalizedPQ):
case(TMG_TF_PQ):
*outTf = EGT_PQ;
break;
default:
return false;
}
return true;
}
enum TMGReturnCode AGMGenerator_SetGMAllocator(
struct AGMGenerator* p_agm_generator,
TMGAlloc allocFunc,
TMGFree freeFunc,
void* memCtx)
{
p_agm_generator->allocFunc = allocFunc;
p_agm_generator->freeFunc = freeFunc;
p_agm_generator->memoryContext = memCtx;
return TMG_RET_OK;
}
enum TMGReturnCode AGMGenerator_ApplyToneMap(
struct AGMGenerator* p_agm_generator,
const struct ToneMapHdrMetaData* streamMetaData,
const struct ToneMapHdrMetaData* dstMetaData,
const enum ToneMapAlgorithm tmAlgorithm,
const struct ToneMappingParameters* tmParams,
bool updateSrcParams,
bool updateDstParams,
bool enableMerge3DLUT)
{
enum TMGReturnCode ret = TMG_RET_OK;
if (!p_agm_generator->initalized) {
AGMGenerator_GMCtor(p_agm_generator);
AGMGenerator_GMSetDefault(p_agm_generator);
p_agm_generator->initalized = true;
}
if ((ret = AGMGenerator_SetAgmOptions(
p_agm_generator,
streamMetaData,
dstMetaData,
tmAlgorithm,
tmParams,
updateSrcParams,
updateDstParams,
enableMerge3DLUT)) != TMG_RET_OK)
goto exit;
if ((ret = AGMGenerator_GMGenerateMap(p_agm_generator)) != TMG_RET_OK)
goto exit;
if ((ret = AGMGenerator_GMGenerate3DLUT(p_agm_generator)) != TMG_RET_OK)
goto exit;
exit:
return ret;
}
enum TMGReturnCode AGMGenerator_SetAgmOptions(
struct AGMGenerator* p_agm_generator,
const struct ToneMapHdrMetaData* srcMetaData,
const struct ToneMapHdrMetaData* dstMetaData,
const enum ToneMapAlgorithm tmAlgorithm,
const struct ToneMappingParameters* tmParams,
bool updateSrcParams,
bool updateDstParams,
bool enableMerge3DLUT)
{
enum TMGReturnCode ret = TMG_RET_OK;
enum cs_gamma_type inGamma;
enum cs_gamma_type outGamma;
if (!TranslateTfEnum(tmParams->shaperTf, &inGamma)) {
ret = TMG_RET_ERROR_INVALID_PARAM;
goto exit;
}
if (!TranslateTfEnum(tmParams->lutOutTf, &outGamma)) {
ret = TMG_RET_ERROR_INVALID_PARAM;
goto exit;
}
if (tmAlgorithm == TMG_A_AGM) {
p_agm_generator->gamutMapParams.gamut_map_mode = EGMM_TM_CHTO;
p_agm_generator->gamutMapParams.hue_rot_mode = EHRM_HR;
}
else {
p_agm_generator->gamutMapParams.gamut_map_mode = EGMM_TM;
p_agm_generator->gamutMapParams.hue_rot_mode = EHRM_NONE;
}
p_agm_generator->gamutMapParams.update_msk = updateSrcParams ? GM_UPDATE_SRC : 0;
p_agm_generator->gamutMapParams.update_msk = updateDstParams ? (p_agm_generator->gamutMapParams.update_msk | GM_UPDATE_DST) : p_agm_generator->gamutMapParams.update_msk;
p_agm_generator->gamutMapParams.ptr_3dlut_rgb = tmParams->lutData;
p_agm_generator->gamutMapParams.num_pnts_3dlut = tmParams->lutDim;
p_agm_generator->gamutMapParams.bitwidth_3dlut = 12;
p_agm_generator->gamutMapParams.en_merge_3dlut = enableMerge3DLUT;
p_agm_generator->gamutMapParams.mode = GM_PQTAB_GBD;
p_agm_generator->gamutMapParams.en_tm_scale_color = 1;
p_agm_generator->gamutMapParams.num_hue_pnts = GM_NUM_HUE;
p_agm_generator->gamutMapParams.num_edge_pnts = GM_NUM_EDGE;
p_agm_generator->gamutMapParams.num_int_pnts = GM_NUM_INT;
p_agm_generator->gamutMapParams.org2_perc_c = GM_ORG2_PERC;
p_agm_generator->gamutMapParams.step_samp = 0.0005; // GM_STEP_SAMP = 0.0001;
p_agm_generator->gamutMapParams.show_pix_mode = ESPM_NONE;
for (int i = 0; i < GM_NUM_PRIM; i++) {
p_agm_generator->gamutMapParams.vec_org1_factor[i] = gm_vec_org13_factor_def[i][0];
p_agm_generator->gamutMapParams.vec_org3_factor[i] = gm_vec_org13_factor_def[i][1];
}
p_agm_generator->gamutMapParams.cs_opts_src.color_space_type = ECST_CUSTOM;
p_agm_generator->gamutMapParams.cs_opts_src.rgbw_xy[0] =
srcMetaData->redPrimaryX / 50000.0;
p_agm_generator->gamutMapParams.cs_opts_src.rgbw_xy[1] =
srcMetaData->redPrimaryY / 50000.0;
p_agm_generator->gamutMapParams.cs_opts_src.rgbw_xy[2] =
srcMetaData->greenPrimaryX / 50000.0;
p_agm_generator->gamutMapParams.cs_opts_src.rgbw_xy[3] =
srcMetaData->greenPrimaryY / 50000.0;
p_agm_generator->gamutMapParams.cs_opts_src.rgbw_xy[4] =
srcMetaData->bluePrimaryX / 50000.0;
p_agm_generator->gamutMapParams.cs_opts_src.rgbw_xy[5] =
srcMetaData->bluePrimaryY / 50000.0;
p_agm_generator->gamutMapParams.cs_opts_src.rgbw_xy[6] =
srcMetaData->whitePointX / 50000.0;
p_agm_generator->gamutMapParams.cs_opts_src.rgbw_xy[7] =
srcMetaData->whitePointY / 50000.0;
p_agm_generator->gamutMapParams.cs_opts_src.gamma_type = inGamma;
p_agm_generator->gamutMapParams.cs_opts_src.luminance_limits[0] = 0;
p_agm_generator->gamutMapParams.cs_opts_src.luminance_limits[1] =
(double)srcMetaData->maxMasteringLuminance;
if (tmParams->shaperTf == TMG_TF_NormalizedPQ) {
p_agm_generator->gamutMapParams.cs_opts_src.pq_norm = (double)tmParams->inputNormalizationFactor;
}
else {
p_agm_generator->gamutMapParams.cs_opts_src.pq_norm = MAX_LUMINANCE;
}
p_agm_generator->gamutMapParams.cs_opts_dst.color_space_type = ECST_CUSTOM;
p_agm_generator->gamutMapParams.cs_opts_dst.rgbw_xy[0] =
dstMetaData->redPrimaryX / 50000.0;
p_agm_generator->gamutMapParams.cs_opts_dst.rgbw_xy[1] =
dstMetaData->redPrimaryY / 50000.0;
p_agm_generator->gamutMapParams.cs_opts_dst.rgbw_xy[2] =
dstMetaData->greenPrimaryX / 50000.0;
p_agm_generator->gamutMapParams.cs_opts_dst.rgbw_xy[3] =
dstMetaData->greenPrimaryY / 50000.0;
p_agm_generator->gamutMapParams.cs_opts_dst.rgbw_xy[4] =
dstMetaData->bluePrimaryX / 50000.0;
p_agm_generator->gamutMapParams.cs_opts_dst.rgbw_xy[5] =
dstMetaData->bluePrimaryY / 50000.0;
p_agm_generator->gamutMapParams.cs_opts_dst.rgbw_xy[6] =
dstMetaData->whitePointX / 50000.0;
p_agm_generator->gamutMapParams.cs_opts_dst.rgbw_xy[7] =
dstMetaData->whitePointY / 50000.0;
p_agm_generator->gamutMapParams.cs_opts_dst.gamma_type = outGamma;
p_agm_generator->gamutMapParams.cs_opts_dst.mode = 0;
p_agm_generator->gamutMapParams.cs_opts_dst.luminance_limits[0] = 0;
p_agm_generator->gamutMapParams.cs_opts_dst.luminance_limits[1] =
(double)dstMetaData->maxMasteringLuminance;
if (tmParams->lutOutTf == TMG_TF_NormalizedPQ) {
p_agm_generator->gamutMapParams.cs_opts_dst.pq_norm = (double)tmParams->inputNormalizationFactor;
}
else {
p_agm_generator->gamutMapParams.cs_opts_dst.pq_norm = MAX_LUMINANCE;
}
// Correct Luminance Bounds if Neccessary
if (p_agm_generator->gamutMapParams.cs_opts_src.luminance_limits[0] > p_agm_generator->gamutMapParams.cs_opts_dst.luminance_limits[0]) {
p_agm_generator->gamutMapParams.cs_opts_src.luminance_limits[0] = p_agm_generator->gamutMapParams.cs_opts_dst.luminance_limits[0];
p_agm_generator->gamutMapParams.update_msk |= GM_UPDATE_SRC;
}
if (p_agm_generator->gamutMapParams.cs_opts_src.luminance_limits[1] < p_agm_generator->gamutMapParams.cs_opts_dst.luminance_limits[1]) {
p_agm_generator->gamutMapParams.cs_opts_src.luminance_limits[1] = p_agm_generator->gamutMapParams.cs_opts_dst.luminance_limits[1];
p_agm_generator->gamutMapParams.update_msk |= GM_UPDATE_SRC;
}
exit:
return ret;
}
void AGMGenerator_GMSetDefault(struct AGMGenerator* p_agm_generator)
{
gm_api_set_def(&p_agm_generator->gamutMapParams);
}
enum TMGReturnCode AGMGenerator_GMGenerateMap(struct AGMGenerator* p_agm_generator)
{
int retcode = gm_api_gen_map(&p_agm_generator->gamutMapParams, &p_agm_generator->agmParams);
return retcode ? TMG_RET_ERROR_GMLIB : TMG_RET_OK;
}
enum TMGReturnCode AGMGenerator_GMGenerate3DLUT(struct AGMGenerator* p_agm_generator)
{
int retcode = gm_api_gen_3dlut(&p_agm_generator->gamutMapParams, &p_agm_generator->agmParams);
return retcode ? TMG_RET_ERROR_GMLIB : TMG_RET_OK;
}
void AGMGenerator_GMCtor(struct AGMGenerator* p_agm_generator)
{
gm_ctor(&p_agm_generator->agmParams, p_agm_generator->allocFunc, p_agm_generator->freeFunc, p_agm_generator->memoryContext);
}
void AGMGenerator_Exit(struct AGMGenerator* p_agm_generator)
{
gm_dtor(&p_agm_generator->agmParams);
}

View file

@ -0,0 +1,354 @@
/* Copyright 2025 Advanced Micro Devices, Inc.
* SPDX-License-Identifier: MIT
*
* Authors: AMD
*
*/
#include "ToneMapGenerator.h"
#include "AGMGenerator.h"
#include "CSCGenerator.h"
#include <stdlib.h>
#include <string.h>
/* Defines comes from ColorPrimaryTable.h */
struct ToneMapHdrMetaData BT2020Container = {
(unsigned short)(0.708 * 50000), (unsigned short)(0.292 * 50000),
(unsigned short)(0.17 * 50000), (unsigned short)(0.797 * 50000),
(unsigned short)(0.131 * 50000), (unsigned short)(0.046 * 50000),
(unsigned short)(0.3127 * 50000), (unsigned short)(0.3290 * 50000),
(unsigned int)(10000 * 10000), (unsigned int)(0.05 * 10000),
(unsigned short)10000,
(unsigned short)10000
};
struct ToneMapHdrMetaData DCIP3Container = {
(unsigned short)(0.68 * 50000), (unsigned short)(0.32 * 50000),
(unsigned short)(0.265 * 50000), (unsigned short)(0.69 * 50000),
(unsigned short)(0.15 * 50000), (unsigned short)(0.06 * 50000),
(unsigned short)(0.3127 * 50000), (unsigned short)(0.3290 * 50000),
(unsigned int)(10000 * 10000), (unsigned int)(0.05 * 10000),
(unsigned short)10000,
(unsigned short)10000
};
struct ToneMapHdrMetaData BT709Container = {
(unsigned short)(0.64 * 50000), (unsigned short)(0.33 * 50000),
(unsigned short)(0.30 * 50000), (unsigned short)(0.60 * 50000),
(unsigned short)(0.15 * 50000), (unsigned short)(0.06 * 50000),
(unsigned short)(0.3127 * 50000), (unsigned short)(0.3290 * 50000),
(unsigned int)(10000 * 10000), (unsigned int)(0.05 * 10000),
(unsigned short)10000,
(unsigned short)10000
};
struct ToneMapHdrMetaData BT601Container = {
(unsigned short)(0.63 * 50000), (unsigned short)(0.34 * 50000),
(unsigned short)(0.31 * 50000), (unsigned short)(0.595 * 50000),
(unsigned short)(0.155 * 50000), (unsigned short)(0.07 * 50000),
(unsigned short)(0.3127 * 50000), (unsigned short)(0.3290 * 50000),
(unsigned int)(10000 * 10000), (unsigned int)(0.05 * 10000),
(unsigned short)10000,
(unsigned short)10000
};
//Function declaration
enum ToneMapColorPrimaries ToneMapGenerator_GetLutColorIn(void);
enum ToneMapColorPrimaries ToneMapGenerator_GetLutColorOut(
enum ToneMapTransferFunction outputContainerGamma,
enum ToneMapColorPrimaries outputContainerPrimaries);
enum ToneMapTransferFunction ToneMapGenerator_GetShaperTf(
enum ToneMapTransferFunction inputContainerGamma);
enum ToneMapTransferFunction ToneMapGenerator_GetLutOutTf(
enum ToneMapTransferFunction outputContainerGamma,
enum ToneMapColorPrimaries outputContainerPrimaries);
unsigned short ToneMapGenerator_GetInputNormFactor(
const struct ToneMapHdrMetaData* streamMetaData);
bool ToneMapGenerator_CacheSrcTmParams(
struct ToneMapGenerator* p_tmGenerator,
const struct ToneMapHdrMetaData* streamMetaData,
enum ToneMapTransferFunction inputContainerGamma);
bool ToneMapGenerator_CacheDstTmParams(
struct ToneMapGenerator* p_tmGenerator,
const struct ToneMapHdrMetaData* dstMetaData,
enum ToneMapTransferFunction outputContainerGamma,
enum ToneMapColorPrimaries outputContainerPrimaries);
enum TMGReturnCode ToneMapGenerator_GenerateLutData(
struct ToneMapGenerator* p_tmGenerator,
const struct ToneMapHdrMetaData* streamMetaData,
const struct ToneMapHdrMetaData* dstMetaData,
enum ToneMapAlgorithm tmAlgorithm,
bool updateSrcParams,
bool updateDstParams,
struct ToneMappingParameters* tmParams);
struct ToneMapHdrMetaData ToneMapGenerator_GetColorContainerData(
enum ToneMapColorPrimaries containerColor);
bool ToneMapGenerator_ContentEqualsContainer(
const struct ToneMapHdrMetaData* contentMetaData,
const struct ToneMapHdrMetaData* containerPrimaries);
enum TMGReturnCode ToneMapGenerator_GenerateToneMappingParameters(
struct ToneMapGenerator* p_tmGenerator,
const struct ToneMapHdrMetaData* streamMetaData,
const struct ToneMapHdrMetaData* dstMetaData,
enum ToneMapTransferFunction inputContainerGamma,
enum ToneMapTransferFunction outputContainerGamma,
enum ToneMapColorPrimaries outputContainerPrimaries,
unsigned short lutDim,
struct ToneMappingParameters* tmParams)
{
enum TMGReturnCode ret = TMG_RET_OK;
bool updateSrcParams;
bool updateDstParams;
if (!p_tmGenerator->memAllocSet) {
ret = TMG_RET_ERROR_NOT_INITIALIZED;
goto exit;
}
tmParams->lutOutTf = ToneMapGenerator_GetLutOutTf(outputContainerGamma, outputContainerPrimaries);
tmParams->lutColorIn = ToneMapGenerator_GetLutColorIn();
tmParams->lutColorOut = ToneMapGenerator_GetLutColorOut(outputContainerGamma, outputContainerPrimaries);
tmParams->shaperTf = ToneMapGenerator_GetShaperTf(inputContainerGamma);
tmParams->formattedLutData = NULL;
tmParams->lutDim = lutDim;
tmParams->inputNormalizationFactor = ToneMapGenerator_GetInputNormFactor(streamMetaData);
updateSrcParams = ToneMapGenerator_CacheSrcTmParams(p_tmGenerator, streamMetaData, inputContainerGamma);
updateDstParams = ToneMapGenerator_CacheDstTmParams(p_tmGenerator, dstMetaData, outputContainerGamma, outputContainerPrimaries);
ret = ToneMapGenerator_GenerateLutData(p_tmGenerator, streamMetaData, dstMetaData, p_tmGenerator->tmAlgo, updateSrcParams, updateDstParams, tmParams);
exit:
return ret;
}
enum ToneMapColorPrimaries ToneMapGenerator_GetLutColorIn()
{
return TMG_CP_BT2020;
}
enum ToneMapColorPrimaries ToneMapGenerator_GetLutColorOut(
enum ToneMapTransferFunction outputContainerGamma,
enum ToneMapColorPrimaries outputContainerPrimaries)
{
enum ToneMapColorPrimaries lutOutPrimaries;
if (outputContainerGamma == TMG_TF_Linear)
lutOutPrimaries = TMG_CP_BT2020;
else
lutOutPrimaries = outputContainerPrimaries;
return lutOutPrimaries;
}
enum ToneMapTransferFunction ToneMapGenerator_GetShaperTf(
enum ToneMapTransferFunction inputContainerGamma)
{
enum ToneMapTransferFunction shaperTf;
switch (inputContainerGamma) {
case(TMG_TF_PQ):
case(TMG_TF_Linear):
shaperTf = TMG_TF_NormalizedPQ;
break;
default:
shaperTf = inputContainerGamma;
break;
}
return shaperTf;
}
enum ToneMapTransferFunction ToneMapGenerator_GetLutOutTf(
enum ToneMapTransferFunction outputContainerGamma,
enum ToneMapColorPrimaries outputContainerPrimaries)
{
enum ToneMapTransferFunction lutOutTf;
if (outputContainerGamma == TMG_TF_Linear ||
outputContainerGamma == TMG_TF_PQ)
lutOutTf = TMG_TF_PQ;
else
lutOutTf = outputContainerGamma;
return lutOutTf;
}
struct ToneMapHdrMetaData ToneMapGenerator_GetColorContainerData(enum ToneMapColorPrimaries containerColor) {
switch (containerColor) {
case (TMG_CP_BT601):
return BT601Container;
break;
case (TMG_CP_BT709):
return BT709Container;
break;
case (TMG_CP_BT2020):
return BT2020Container;
break;
case (TMG_CP_DCIP3):
return DCIP3Container;
break;
default:
return BT2020Container;
break;
}
}
unsigned short ToneMapGenerator_GetInputNormFactor(const struct ToneMapHdrMetaData* streamMetaData) {
unsigned short normFactor;
if (streamMetaData->maxMasteringLuminance < INPUT_NORMALIZATION_FACTOR)
normFactor = INPUT_NORMALIZATION_FACTOR;
else
normFactor = streamMetaData->maxMasteringLuminance;
return normFactor;
}
bool ToneMapGenerator_ContentEqualsContainer(
const struct ToneMapHdrMetaData* contentMetaData,
const struct ToneMapHdrMetaData* containerPrimaries)
{
if (abs(contentMetaData->bluePrimaryX - containerPrimaries->redPrimaryX) < 2 &&
abs(contentMetaData->redPrimaryY - containerPrimaries->redPrimaryY) < 2 &&
abs(contentMetaData->greenPrimaryX - containerPrimaries->greenPrimaryX) < 2 &&
abs(contentMetaData->greenPrimaryY - containerPrimaries->greenPrimaryY) < 2 &&
abs(contentMetaData->bluePrimaryX - containerPrimaries->bluePrimaryX) < 2 &&
abs(contentMetaData->bluePrimaryY - containerPrimaries->bluePrimaryY) < 2)
return true;
else
return false;
}
/*
Tone map generation consists of three steps:
1. Container to content color space conversion.
2. Tone mapping and gamut mapping operation.
3. Content to output container color space conversion.
These operations are cascaded one after the other. The enable3DLUTMerge will tell each module
whether or not to start from scratch, or use the previous blocks output as the nextbloack input.
The terminology "Content Color Space / Container Color Space" is used to distinguish
between the color volume of the content and the color volume of the container.
For example, the content color volume might be DCIP3 and the Container might be BT2020.
CSC step changes the representation of the content to align with its color volume.
*/
enum TMGReturnCode ToneMapGenerator_GenerateLutData(
struct ToneMapGenerator* p_tmGenerator,
const struct ToneMapHdrMetaData* streamMetaData,
const struct ToneMapHdrMetaData* dstMetaData,
enum ToneMapAlgorithm tmAlgorithm,
bool updateSrcParams,
bool updateDstParams,
struct ToneMappingParameters* tmParams)
{
bool enable3DLUTMerge = false;
struct ToneMapHdrMetaData lutContainer = ToneMapGenerator_GetColorContainerData(tmParams->lutColorIn);
if (!ToneMapGenerator_ContentEqualsContainer(streamMetaData, &lutContainer)) {
lutContainer.maxMasteringLuminance = streamMetaData->maxMasteringLuminance;
lutContainer.minMasteringLuminance = streamMetaData->minMasteringLuminance;
CSCGenerator_ApplyCSC(
&lutContainer,
tmParams->shaperTf,
streamMetaData,
tmParams->shaperTf,
tmParams,
enable3DLUTMerge);
enable3DLUTMerge = true;
}
AGMGenerator_ApplyToneMap(
&p_tmGenerator->agmGenerator,
streamMetaData,
dstMetaData,
tmAlgorithm,
tmParams,
updateSrcParams,
updateDstParams,
enable3DLUTMerge);
enable3DLUTMerge = true;
lutContainer = ToneMapGenerator_GetColorContainerData(tmParams->lutColorOut);
if (!ToneMapGenerator_ContentEqualsContainer(dstMetaData, &lutContainer)) {
lutContainer.maxMasteringLuminance = dstMetaData->maxMasteringLuminance;
lutContainer.minMasteringLuminance = dstMetaData->minMasteringLuminance;
CSCGenerator_ApplyCSC(
dstMetaData,
tmParams->lutOutTf,
&lutContainer,
tmParams->lutOutTf,
tmParams,
enable3DLUTMerge
);
}
return TMG_RET_OK;
}
bool ToneMapGenerator_CacheSrcTmParams(
struct ToneMapGenerator* p_tmGenerator,
const struct ToneMapHdrMetaData* streamMetaData,
enum ToneMapTransferFunction inputContainerGamma)
{
bool updateSrcParams = memcmp(streamMetaData, &p_tmGenerator->cachedSrcTmParams.streamMetaData, sizeof(struct ToneMapHdrMetaData)) ||
inputContainerGamma != p_tmGenerator->cachedSrcTmParams.inputContainerGamma;
if (updateSrcParams) {
memcpy(&p_tmGenerator->cachedSrcTmParams.streamMetaData, streamMetaData, sizeof(struct ToneMapHdrMetaData));
p_tmGenerator->cachedSrcTmParams.inputContainerGamma = inputContainerGamma;
}
return updateSrcParams;
}
bool ToneMapGenerator_CacheDstTmParams(
struct ToneMapGenerator* p_tmGenerator,
const struct ToneMapHdrMetaData* dstMetaData,
enum ToneMapTransferFunction outputContainerGamma,
enum ToneMapColorPrimaries outputContainerPrimaries)
{
bool updateDstParams = memcmp(dstMetaData, &p_tmGenerator->cachedDstTmParams.dstMetaData, sizeof(struct ToneMapHdrMetaData)) ||
outputContainerGamma != p_tmGenerator->cachedDstTmParams.outputContainerGamma ||
outputContainerPrimaries != p_tmGenerator->cachedDstTmParams.outputContainerPrimaries;
if (updateDstParams){
memcpy(&p_tmGenerator->cachedDstTmParams.dstMetaData, dstMetaData, sizeof(struct ToneMapHdrMetaData));
p_tmGenerator->cachedDstTmParams.outputContainerGamma = outputContainerGamma;
p_tmGenerator->cachedDstTmParams.outputContainerPrimaries = outputContainerPrimaries;
p_tmGenerator->cachedDstTmParams.outputContainerPrimaries = outputContainerPrimaries;
}
return updateDstParams;
}
enum TMGReturnCode ToneMapGenerator_SetInternalAllocators(
struct ToneMapGenerator* p_tmGenerator,
TMGAlloc allocFunc,
TMGFree freeFunc,
void* memCtx)
{
enum TMGReturnCode ret = AGMGenerator_SetGMAllocator(
&p_tmGenerator->agmGenerator,
allocFunc,
freeFunc,
memCtx);
p_tmGenerator->memAllocSet = true;
return ret;
}

1418
src/amd/gmlib/gm/cs_funcs.c Executable file

File diff suppressed because it is too large Load diff

273
src/amd/gmlib/gm/cs_funcs.h Executable file
View file

@ -0,0 +1,273 @@
/*
* Copyright 2025 Advanced Micro Devices, Inc.
* SPDX-License-Identifier: MIT
*
*----------------------------------------------------------------------
* File Name : cs_funcs.h
* Purpose : Color Space functions
* Author : Vladimir Lachine (vlachine@amd.com)
* Date : September 20, 2023
* Version : 1.4
*-------------------------------------------------------------------------
*
*/
#pragma once
#include "mat_funcs.h"
#ifdef __cplusplus
extern "C" {
#endif
#define CS_MAX_LUMINANCE 10000.0
#define CS_SCALE_CCCS 125.0
#define CS_CHAD_D65 0x01 /* apply chromatic adaptation */
static MATFLOAT cs_mat_709_2020[3][3] = { /* BT.2087 */
{0.6274, 0.3293, 0.0433},
{0.0691, 0.9195, 0.0114},
{0.0164, 0.0880, 0.8956}
};
enum cs_white_point_type {
EWPT_NONE = 0, /* NATIVE */
EWPT_A = 1,
EWPT_B = 2,
EWPT_C = 3,
EWPT_D50 = 4,
EWPT_D55 = 5,
EWPT_D65 = 6, /* 709, sRRGB, ADOBE, APPLE */
EWPT_D75 = 7,
EWPT_9300 = 8,
EWPT_E = 9,
EWPT_F2 = 10,
EWPT_F7 = 11,
EWPT_F11 = 12,
EWPT_DCIP3 = 13, /* DCI-P3 */
EWPT_11000 = 14, /* 11000K */
EWPT_NUM = 15 /* CUSTOM */
};
enum cs_gamma_type {
EGT_LINEAR = 0, /* LINEAR */
EGT_709 = 1, /* 709 (SD/HD) */
EGT_ADOBE = 2, /* ADOBE 1998 */
EGT_DCIP3 = 3, /* DCI-P3 */
EGT_APPLE = 4, /* APPLE */
EGT_sRGB = 5, /* sRGB */
EGT_PQ = 6, /* PQ */
EGT_HLG = 7, /* HLG */
EGT_2_2 = 8, /* 2.2 */
EGT_2_4 = 9, /* 2.4 */
EGT_CUSTOM = 10 /* CUSTOM */
};
enum cs_color_space_type {
ECST_709 = 0, /* 709(HD),sRGB */
ECST_SMPTE = 1, /* SMPTE RP125 (SD) */
ECST_ADOBE = 2, /* ADOBE 1998 */
ECST_DCIP3 = 3, /* DCI-P3 */
ECST_APPLE = 4, /* APPLE */
ECST_EBU = 5, /* EBU 3213 (576i) */
ECST_NTSC = 6, /* NTSC 1953 */
ECST_CIE = 7, /* CIE */
ECST_BT2020 = 8, /* BT.2020 */
ECST_CUSTOM = 9 /* CUSTOM */
};
enum cs_gamma_dir {
EGD_NONLIN_2_LIN = 0,
EGD_LIN_2_NONLIN = 1
};
struct s_cs_opts {
/* Color Space Type: [0,9]=0 : 0-709, 1-SMPTE, 2-ADOBE1998, 3-DCI-P3, 4-APPLE,
5-EBU3213, 6-NTSC, 7-CIE, 8-BT2020, 9-CUSTOM */
enum cs_color_space_type color_space_type;
/* Gamma Type: [0,9]=1 : 0-LINEAR, 1-709, 2-ADOBE, 3-DCI-P3, 4-APPLE,
5-sRGB, 6-PQ, 7-HLG, 8-G2.2, 9-G2.4, 10-CUSTOM */
enum cs_gamma_type gamma_type;
MATFLOAT luminance_limits[2]; /* luminance min/max in a range [0.0,10000.0]= {0.0,400.0} */
MATFLOAT pq_norm; /* normalizatiion luminance for PQ: [0.0,10000.0] = 0.0 - no normalization */
unsigned int mode; /* mode: {0,1}=0 : Enable/disable Chromatic adaptation */
MATFLOAT rgbw_xy[8]; /* Chromaticity: Red, Green, Blue, White in xy */
MATFLOAT gamma_parm[4]; /* Gamma parameters: (0.0,?,?,?) - PQ, (0.5,?,?,?) - HLG */
};
struct s_color_space {
/* input parameters */
/* cs_color_space_type: [0,9]=9 : 0-709, 1-SMPTE, 2-ADOBE1998, 3-DCI-P3, 4-APPLE,
5-EBU3213, 6-NTSC, 7-CIE, 8-BT2020, 9-CUSTOM */
enum cs_color_space_type color_space_type;
/* cs_gamma_type: [0,9]=9 : 0-LINEAR, 1-709, 2-ADOBE, 3-DCI-P3, 4-APPLE,
5-sRGB, 6-PQ, 7-HLG, 8-Gamma2.2, 9-CUSTOM */
enum cs_gamma_type gamma_type;
/* luminances min/max/range normilized to 10000.0 in a range [0.0,1.0]=0.0,1.0,1.0 */
MATFLOAT luminance_limits[3];
MATFLOAT pq_norm; /* normalizatiion luminance for PQ: [0.0,10000.0] = 0.0 - no normalization */
unsigned int mode; /* mode: {0,1}=0 : CS_CHAD_D65 - Enable Chromatic Adaptation */
/* custom or initialized parameters based on input parameters */
MATFLOAT rgbw_xy[8]; /* Red, Green, Blue, White in xy */
MATFLOAT gamma_parm[4]; /* Gamma parameters: 0.0,?,?,? - PQ, 0.5,?,?,? - HLG */
/* calculated variables */
MATFLOAT luma_limits[3]; /* Min/max/range luma (PQ) normilized to 10000 : [0.0,1.0]=0,1,1 */
MATFLOAT mat_rgb2xyz[3][3]; /* RGB to XYZ matrix */
MATFLOAT mat_xyz2rgb[3][3]; /* XYZ to RGB matrix */
MATFLOAT mat_rgb2lms[3][3]; /* RGB to LMS matrix */
MATFLOAT mat_lms2rgb[3][3]; /* LMS to RGB matrix */
MATFLOAT mat_lms2itp[3][3]; /* LMS to ITP matrix */
MATFLOAT mat_itp2lms[3][3]; /* ITP to LMS matrix */
MATFLOAT mat_chad[3][3]; /* Chromatic Adaptation matrix */
MATFLOAT white_xyz[3]; /* White in XYZ */
int cct; /* Correlated Color Temperature */
MATFLOAT hlg_system_gamma; /* HLG OOTF system gamma for */
MATFLOAT hlg_beta; /* user black level lift */
};
/* get internal constants */
const MATFLOAT *cs_get_gamma(enum cs_gamma_type gamma_type);
const MATFLOAT *cs_get_color_space(enum cs_color_space_type color_space_type);
const MATFLOAT *cs_get_white_point(enum cs_white_point_type white_point_type);
/* initilize color space functions */
void cs_set_opts_def(struct s_cs_opts *ptr_cs_opts);
void cs_init(struct s_cs_opts *ptr_cs_opts, struct s_color_space *ptr_color_space);
void cs_init_private(struct s_color_space *ptr_color_space);
void cs_copy(struct s_color_space *ptr_color_space_src, struct s_color_space *ptr_color_space_dst);
void cs_luminance_to_luma_limits(MATFLOAT luminance_limits[2], MATFLOAT luma_limits[3]);
/* color formats conversion functions */
void cs_xyy_to_xyz(MATFLOAT xyy_inp[3], MATFLOAT xyz_out[3]);
void cs_xyz_to_xyy(MATFLOAT xyz_inp[3], MATFLOAT xyy_out[3]);
void cs_xyzc_to_xyz(MATFLOAT xyz_inp[3], MATFLOAT xyz_out[3]);
void cs_xyz_to_xyzc(MATFLOAT xyz_inp[3], MATFLOAT xyz_out[3]);
void cs_rgb_to_itp(struct s_color_space *ptr_color_space, MATFLOAT rgb_inp[3], MATFLOAT itp_out[3]);
void cs_itp_to_rgb(struct s_color_space *ptr_color_space, MATFLOAT itp_inp[3], MATFLOAT rgb_out[3]);
void cs_ich_to_itp(MATFLOAT ich_inp[3], MATFLOAT itp_out[3]);
void cs_itp_to_ich(MATFLOAT itp_inp[3], MATFLOAT ich_out[3]);
void cs_rgb_to_yuv(MATFLOAT rgb_inp[3], MATFLOAT yuv_out[3]);
void cs_yuv_to_rgb(MATFLOAT yuv_inp[3], MATFLOAT rgb_out[3]);
MATFLOAT cs_nlin_to_lin(struct s_color_space *ptr_color_space, MATFLOAT val_inp);
void cs_nlin_to_lin_rgb(struct s_color_space *ptr_color_space, MATFLOAT rgb_inp[3], MATFLOAT rgb_out[3]);
MATFLOAT cs_lin_to_nlin(struct s_color_space *ptr_color_space, MATFLOAT val_inp);
void cs_lin_to_nlin_rgb(struct s_color_space *ptr_color_space, MATFLOAT rgb_inp[3], MATFLOAT rgb_out[3]);
/* internal matrixes genereation functions */
int cs_genmat_rgb_to_xyz(MATFLOAT rgbw_xy[8], MATFLOAT mat_rgb2xyz[3][3]);
int cs_genmat_xyz_to_rgb(MATFLOAT rgbw_xy[8], MATFLOAT mat_xyz2rgb[3][3]);
int cs_genmat_rgb_to_rgb(MATFLOAT rgbw_xy_src[8], MATFLOAT rgbw_xy_dst[8], MATFLOAT mat_rgb2rgb[3][3], int en_chad);
int cs_genmat_chad(MATFLOAT white_xy_src[2], MATFLOAT white_xy_dst[2], MATFLOAT mat_chad[3][3]);
/* gamma curves generation functions */
MATFLOAT cs_gamma(MATFLOAT val, MATFLOAT gamma_parm[4], enum cs_gamma_dir gamma_dir);
MATFLOAT cs_gamma_pq(MATFLOAT val, enum cs_gamma_dir gamma_dir);
MATFLOAT cs_gamma_1886(MATFLOAT val, MATFLOAT lb, MATFLOAT lw, MATFLOAT gamma);
void cs_pq_ootf(MATFLOAT rgb_inp[3], MATFLOAT rgb_out[3]);
void cs_sdr_to_pq(MATFLOAT rgb_inp[3], MATFLOAT rgb_out[3], MATFLOAT en_709_2020);
void cs_gamma_rgb(MATFLOAT rgb_inp[3], MATFLOAT rgb_out[3], MATFLOAT gamma_parm[4], enum cs_gamma_dir gamma_dir);
/* signal clipping functions */
int cs_min_rgb(MATFLOAT rgb[3], MATFLOAT val_min);
int cs_max_rgb(MATFLOAT rgb[3], MATFLOAT val_max);
/* signal validation functions */
int cs_is_valid_itp(struct s_color_space *ptr_color_space, MATFLOAT itp[3]);
int cs_is_valid_ic(struct s_color_space *ptr_color_space, MATFLOAT pnt_ic[2], MATFLOAT hue_sin_cos[2]);
int cs_is_valid_rgb(MATFLOAT rgb[3], MATFLOAT val_min, MATFLOAT val_max);
int cs_clip_rgb(MATFLOAT rgb[3], MATFLOAT val_min, MATFLOAT val_max);
void cs_clamp_rgb(MATFLOAT rgb[3], MATFLOAT val_min, MATFLOAT val_max);
/* signal normalization functions */
void cs_norm_rgb(MATFLOAT rgb[3], MATFLOAT val_min, MATFLOAT val_rng);
void cs_denorm_rgb(MATFLOAT rgb[3], MATFLOAT val_min, MATFLOAT val_rng);
/* signal format conversion functions */
void cs_int2flt_rgb(int rgb_inp[3], MATFLOAT rgb_out[3], int val_max);
void cs_flt2int_rgb(MATFLOAT rgb_inp[3], int rgb_out[3], int val_max);
void cs_short2flt_rgb(unsigned short rgb_inp[3], MATFLOAT rgb_out[3], int val_max);
void cs_flt2short_rgb(MATFLOAT rgb_inp[3], unsigned short rgb_out[3], int val_max);
void cs_genprim_itp(struct s_color_space *ptr_color_space,
int num_prim, MATFLOAT *ptr_prim_rgb, MATFLOAT *ptr_prim_ich);
/* gamma curve handling functions */
MATFLOAT cs_soft_clip(MATFLOAT val, MATFLOAT limits_src[3], MATFLOAT limits_dst[3]);
MATFLOAT cs_gamma_to_gamma(MATFLOAT val, enum cs_gamma_type gamma_type_src, enum cs_gamma_type gamma_type_dst,
MATFLOAT luminance_limits_dst[3], MATFLOAT luma_limits_src[3], MATFLOAT luma_limits_dst[3],
MATFLOAT(*func_pq_to_pq)(MATFLOAT), int en_norm, int en_soft_clip);
/* CCT handling functions */
#define CS_CCT_MIN 1000
#define CS_CCT_MAX 20000
#define CS_CCT_INC 100
#define CS_CCT_SIZE ((CS_CCT_MAX - CS_CCT_MIN) / CS_CCT_INC + 1)
int cs_xy_to_cct(MATFLOAT white_xy[2]);
void cs_cct_to_xy(int cct, MATFLOAT xy[2]);
void cs_csc(struct s_color_space *ptr_cs_src, struct s_color_space *ptr_cs_dst,
MATFLOAT rgb_inp[3], MATFLOAT rgb_out[3], int en_chad);
int cs_is_space(struct s_color_space *ptr_color_space,
enum cs_color_space_type color_space_type, enum cs_gamma_type gamma_type);
void cs_init_type(MATFLOAT luminance_limits[2],
enum cs_color_space_type color_space_type, enum cs_gamma_type gamma_type,
struct s_color_space *ptr_color_space);
void cs_init_BT709(MATFLOAT luminance_limits[2], struct s_color_space *ptr_color_space);
void cs_init_BT2100(MATFLOAT luminance_limits[2], struct s_color_space *ptr_color_space);
void cs_rgb_to_ycbcr2020(MATFLOAT rgb_inp[3], MATFLOAT ycbcr_out[3]);
MATFLOAT cs_ootf_gamma_peak(MATFLOAT gamma, MATFLOAT luminance_peak);
MATFLOAT cs_ootf_gamma_amb(MATFLOAT gamma, MATFLOAT luminance_ambient);
MATFLOAT cs_gamma_adjust_sdr(MATFLOAT gamma, MATFLOAT luminance_peak);
MATFLOAT cs_gamma_adjust(MATFLOAT gamma, MATFLOAT luminance_peak, MATFLOAT luminance_amb);
void cs_chad_gains(MATFLOAT rgbw_xy[8], MATFLOAT w_xy[2], MATFLOAT rgb_gain[3]);
void cs_genmat_cct(struct s_color_space *ptr_cs, int cct_shift, int norm, MATFLOAT mat_cct[3][3]);
/* HSV functions */
int cs_rgb_to_vsh(MATFLOAT rgb[3], MATFLOAT vsh[3]);
void cs_vsh_to_rgb(MATFLOAT vsh[3], MATFLOAT rgb[3]);
/* YUV functions */
void cs_yuv_to_ysh(MATFLOAT yuv_inp[3], MATFLOAT ysh_out[3]);
void cs_ysh_to_yuv(MATFLOAT ysh_inp[3], MATFLOAT yuv_out[3]);
/* CIELAB functions */
#define CS_LAB_E 0.008856
#define CS_LAB_K 903.3
void cs_rgb_to_lab(MATFLOAT rgb[3], MATFLOAT lab[3], struct s_color_space *ptr_color_space);
void cs_lab_to_rgb(MATFLOAT lab[3], MATFLOAT rgb[3], struct s_color_space *ptr_color_space);
void cs_xyz_to_lab(MATFLOAT xyz[3], MATFLOAT lab[3], MATFLOAT white_xyz[3]);
void cs_lab_to_xyz(MATFLOAT lab[3], MATFLOAT xyz[3], MATFLOAT white_xyz[3]);
MATFLOAT cs_de94(MATFLOAT lab0[3], MATFLOAT lab1[3]);
/* HLG functions */
MATFLOAT cs_gamma_hlg(MATFLOAT val, enum cs_gamma_dir gamma_dir);
void cs_hlg_ootf(MATFLOAT rgb_inp[3], MATFLOAT rgb_out[3], MATFLOAT luminance_peak, MATFLOAT system_gamma);
void cs_hlg_ootf_inv(MATFLOAT rgb_inp[3], MATFLOAT rgb_out[3], MATFLOAT luminance_peak, MATFLOAT gamma);
void cs_hlg_oetf(MATFLOAT rgb_inp[3], MATFLOAT rgb_out[3], MATFLOAT luminance_peak, MATFLOAT system_gamma);
void cs_hlg_eotf(MATFLOAT rgb_inp[3], MATFLOAT rgb_out[3], MATFLOAT luminance_limits[3],
MATFLOAT system_gamma, MATFLOAT beta);
MATFLOAT cs_hlg_system_gamma(MATFLOAT peak_luminance);
#if 0
void cs_pq_to_hlg(MATFLOAT rgb_inp[3], MATFLOAT rgb_out[3], MATFLOAT luminance_peak, MATFLOAT system_gamma);
void cs_hlg_to_pq(MATFLOAT rgb_inp[3], MATFLOAT rgb_out[3], MATFLOAT vec_luminance[3],
MATFLOAT system_gamma, MATFLOAT beta);
void cs_sdr_to_hlg(MATFLOAT rgb_inp[3], MATFLOAT rgb_out[3], MATFLOAT en_709_2020);
#endif
#ifdef __cplusplus
}
#endif

View file

@ -0,0 +1,75 @@
/*
* Copyright 2025 Advanced Micro Devices, Inc.
* SPDX-License-Identifier: MIT
*
*----------------------------------------------------------------------
* File Name : csc_api_funcs.c
* Purpose : Color Space Conversion 3DLUT functions
* Author : Vladimir Lachine (vlachine@amd.com)
* Date : June 09, 2023
* Version : 1.2
*----------------------------------------------------------------------
*
*/
#ifndef GM_SIM
#pragma code_seg("PAGED3PC")
#pragma data_seg("PAGED3PD")
#pragma const_seg("PAGED3PR")
#endif
#include "csc_api_funcs.h"
void csc_api_set_def(struct s_csc_api_opts *ptr_csc_api_opts)
{
cs_set_opts_def(&ptr_csc_api_opts->cs_opts_src);
cs_set_opts_def(&ptr_csc_api_opts->cs_opts_dst);
ptr_csc_api_opts->en_chad = 0;
/* 3DLUT */
ptr_csc_api_opts->en_merge_3dlut = 0;
ptr_csc_api_opts->num_pnts_3dlut = 17;
ptr_csc_api_opts->bitwidth_3dlut = 12;
ptr_csc_api_opts->ptr_3dlut_rgb = 0;
}
int csc_api_gen_map(struct s_csc_api_opts *ptr_csc_api_opts, struct s_csc_map *ptr_csc_map)
{
cs_init(&ptr_csc_api_opts->cs_opts_src, &ptr_csc_map->color_space_src);
cs_init(&ptr_csc_api_opts->cs_opts_dst, &ptr_csc_map->color_space_dst);
ptr_csc_map->en_chad = ptr_csc_api_opts->en_chad;
return csc_init_map(ptr_csc_map);
}
int csc_api_gen_3dlut(struct s_csc_api_opts *ptr_csc_api_opts, struct s_csc_map *ptr_csc_map)
{
int index = 0;
int value_max = (1 << ptr_csc_api_opts->bitwidth_3dlut) - 1;
int nir, nig, nib;
if (ptr_csc_api_opts->ptr_3dlut_rgb == 0)
return -1; /* something wrong */
for (nir = 0; nir < ptr_csc_api_opts->num_pnts_3dlut; nir++)
for (nig = 0; nig < ptr_csc_api_opts->num_pnts_3dlut; nig++)
for (nib = 0; nib < ptr_csc_api_opts->num_pnts_3dlut; nib++) {
unsigned short rgb[3];
MATFLOAT rgb_inp[3], rgb_out[3];
rgb[0] = ptr_csc_api_opts->en_merge_3dlut ? ptr_csc_api_opts->ptr_3dlut_rgb[index + 0] :
(nir * value_max) / (ptr_csc_api_opts->num_pnts_3dlut - 1);
rgb[1] = ptr_csc_api_opts->en_merge_3dlut ? ptr_csc_api_opts->ptr_3dlut_rgb[index + 1] :
(nig * value_max) / (ptr_csc_api_opts->num_pnts_3dlut - 1);
rgb[2] = ptr_csc_api_opts->en_merge_3dlut ? ptr_csc_api_opts->ptr_3dlut_rgb[index + 2] :
(nib * value_max) / (ptr_csc_api_opts->num_pnts_3dlut - 1);
cs_short2flt_rgb(rgb, rgb_inp, value_max);
csc_rgb_to_rgb(ptr_csc_map, rgb_inp, rgb_out);
cs_flt2short_rgb(rgb_out, &ptr_csc_api_opts->ptr_3dlut_rgb[index], value_max);
index += 3;
}
return 0;
}

View file

@ -0,0 +1,41 @@
/*
* Copyright 2025 Advanced Micro Devices, Inc.
* SPDX-License-Identifier: MIT
*
*----------------------------------------------------------------------
* File Name : csc_api_funcs.h
* Purpose : Color Space Conversion 3DLUT functions
* Author : Vladimir Lachine (vlachine@amd.com)
* Date : June 09, 2023
* Version : 1.2
*----------------------------------------------------------------------
*
*/
#pragma once
#include "csc_funcs.h"
#ifdef __cplusplus
extern "C" {
#endif
struct s_csc_api_opts { /* csc parameters */
int en_chad; /* enable/disable chromatic adaptation: {0,1}=0 */
struct s_cs_opts cs_opts_src; /* Source color space */
struct s_cs_opts cs_opts_dst; /* Destination color space */
/* 3DLUT parameters */
int en_merge_3dlut;
int num_pnts_3dlut;
int bitwidth_3dlut;
unsigned short *ptr_3dlut_rgb;
};
void csc_api_set_def(struct s_csc_api_opts *ptr_csc_api_opts);
int csc_api_gen_map(struct s_csc_api_opts *ptr_csc_api_opts, struct s_csc_map *ptr_csc_map);
int csc_api_gen_3dlut(struct s_csc_api_opts *ptr_csc_api_opts, struct s_csc_map *ptr_csc_map);
#ifdef __cplusplus
}
#endif

56
src/amd/gmlib/gm/csc_funcs.c Executable file
View file

@ -0,0 +1,56 @@
/*
* Copyright 2025 Advanced Micro Devices, Inc.
* SPDX-License-Identifier: MIT
*
*----------------------------------------------------------------------
* File Name : csc_funcs.c
* Purpose : Color Space Conversion 3DLUT functions
* Author : Vladimir Lachine (vlachine@amd.com)
* Date : June 09, 2023
* Version : 1.2
*----------------------------------------------------------------------
*
*/
#ifndef GM_SIM
#pragma code_seg("PAGED3PC")
#pragma data_seg("PAGED3PD")
#pragma const_seg("PAGED3PR")
#endif
#include "csc_funcs.h"
void csc_ctor(struct s_csc_map *ptr_csc_map)
{
csc_set_def(ptr_csc_map);
}
void csc_dtor(struct s_csc_map *ptr_csc_map)
{
}
void csc_set_def(struct s_csc_map *ptr_csc_map)
{
ptr_csc_map->en_chad = 0;
mat_3x3_unity(ptr_csc_map->mat_csc);
}
int csc_init_map(struct s_csc_map *ptr_csc_map)
{
cs_genmat_rgb_to_rgb(ptr_csc_map->color_space_src.rgbw_xy, ptr_csc_map->color_space_dst.rgbw_xy,
ptr_csc_map->mat_csc, ptr_csc_map->en_chad);
return 0;
}
int csc_rgb_to_rgb(struct s_csc_map *ptr_csc_map, MATFLOAT rgb_inp[3], MATFLOAT rgb_out[3])
{
MATFLOAT rgb_tmp[3];
cs_nlin_to_lin_rgb(&ptr_csc_map->color_space_src, rgb_inp, rgb_tmp);
mat_eval_3x3(ptr_csc_map->mat_csc, rgb_tmp, rgb_out);
cs_clamp_rgb(rgb_out, 0.0, 1.0);
cs_lin_to_nlin_rgb(&ptr_csc_map->color_space_dst, rgb_out, rgb_out);
return 0;
}

41
src/amd/gmlib/gm/csc_funcs.h Executable file
View file

@ -0,0 +1,41 @@
/*
* Copyright 2025 Advanced Micro Devices, Inc.
* SPDX-License-Identifier: MIT
*
*----------------------------------------------------------------------
* File Name : csc_funcs.h
* Purpose : Color Space Conversion 3DLUT functions
* Author : Vladimir Lachine (vlachine@amd.com)
* Date : June 09, 2023
* Version : 1.2
*----------------------------------------------------------------------
*
*/
#pragma once
#include "cs_funcs.h"
#ifdef __cplusplus
extern "C" {
#endif
struct s_csc_map {
int en_chad; /* enable/disable chromatic adaptation: {0,1}=0 */
struct s_color_space color_space_src; /* Source color space */
struct s_color_space color_space_dst; /* Destination color space */
MATFLOAT mat_csc[3][3]; /* color space conversion matrix */
};
/* constructor and destructor */
void csc_ctor(struct s_csc_map *ptr_csc_map);
void csc_dtor(struct s_csc_map *ptr_csc_map);
void csc_set_def(struct s_csc_map *ptr_csc_map);
int csc_init_map(struct s_csc_map *ptr_csc_map);
int csc_rgb_to_rgb(struct s_csc_map *ptr_csc_map, MATFLOAT rgb_inp[3], MATFLOAT rgb_out[3]);
#ifdef __cplusplus
}
#endif

View file

@ -0,0 +1,85 @@
/*
* Copyright 2025 Advanced Micro Devices, Inc.
* SPDX-License-Identifier: MIT
*
*----------------------------------------------------------------------
* File Name : cvd_api_funcs.c
* Purpose : Color Vision Deficiency functions
* Author : Vladimir Lachine (vlachine@amd.com)
* Date : January 21, 2020
* Version : 1.0
*----------------------------------------------------------------------
*
*/
#ifndef GM_SIM
#pragma code_seg("PAGED3PC")
#pragma data_seg("PAGED3PD")
#pragma const_seg("PAGED3PR")
#endif
#include "cvd_api_funcs.h"
void cvd_api_set_def(struct s_cvd_api_opts *ptr_api_cvd_opts)
{
int nk;
ptr_api_cvd_opts->mode = ECM_NONE;
for (nk = 0; nk < 3; nk++)
ptr_api_cvd_opts->gain[nk] = 0.0;
cs_set_opts_def(&ptr_api_cvd_opts->cs_opts);
ptr_api_cvd_opts->en_merge_3dlut = 0;
ptr_api_cvd_opts->num_pnts_3dlut = 17;
ptr_api_cvd_opts->bitwidth_3dlut = 12;
ptr_api_cvd_opts->ptr_3dlut_rgb = 0;
}
int cvd_api_gen_map(struct s_cvd_api_opts *ptr_api_cvd_opts, struct s_cvd_map *ptr_cvd_map)
{
int nk;
cvd_set_def(ptr_cvd_map);
ptr_cvd_map->mode = ptr_api_cvd_opts->mode;
for (nk = 0; nk < 3; nk++)
ptr_cvd_map->gain[nk] = ptr_api_cvd_opts->gain[nk];
cs_init(&ptr_api_cvd_opts->cs_opts, &ptr_cvd_map->color_space);
return 0;
}
int cvd_api_gen_3dlut(struct s_cvd_api_opts *ptr_api_cvd_opts, struct s_cvd_map *ptr_cvd_map)
{
int index = 0;
int nir, nig, nib;
int value_max;
if (ptr_api_cvd_opts->ptr_3dlut_rgb == 0)
return -1; /* something wrong */
value_max = (1 << ptr_api_cvd_opts->bitwidth_3dlut) - 1;
for (nir = 0; nir < ptr_api_cvd_opts->num_pnts_3dlut; nir++)
for (nig = 0; nig < ptr_api_cvd_opts->num_pnts_3dlut; nig++)
for (nib = 0; nib < ptr_api_cvd_opts->num_pnts_3dlut; nib++) {
unsigned short rgb[3];
MATFLOAT rgb_inp[3], rgb_out[3];
rgb[0] = ptr_api_cvd_opts->en_merge_3dlut ? ptr_api_cvd_opts->ptr_3dlut_rgb[index + 0] :
(nir * value_max) / (ptr_api_cvd_opts->num_pnts_3dlut - 1);
rgb[1] = ptr_api_cvd_opts->en_merge_3dlut ? ptr_api_cvd_opts->ptr_3dlut_rgb[index + 1] :
(nig * value_max) / (ptr_api_cvd_opts->num_pnts_3dlut - 1);
rgb[2] = ptr_api_cvd_opts->en_merge_3dlut ? ptr_api_cvd_opts->ptr_3dlut_rgb[index + 2] :
(nib * value_max) / (ptr_api_cvd_opts->num_pnts_3dlut - 1);
cs_short2flt_rgb(rgb, rgb_inp, value_max);
cvd_rgb_to_rgb(ptr_cvd_map, rgb_inp, rgb_out);
cs_flt2short_rgb(rgb_out, &ptr_api_cvd_opts->ptr_3dlut_rgb[index], value_max);
index += 3;
}
return 0;
}

View file

@ -0,0 +1,42 @@
/*
* Copyright 2025 Advanced Micro Devices, Inc.
* SPDX-License-Identifier: MIT
*
*----------------------------------------------------------------------
* File Name : cvd_api_funcs.h
* Purpose : Color Vision Deficiency functions
* Author : Vladimir Lachine (vlachine@amd.com)
* Date : January 21, 2020
* Version : 1.0
*----------------------------------------------------------------------
*
*/
#pragma once
#include "cvd_funcs.h"
#ifdef __cplusplus
extern "C" {
#endif
struct s_cvd_api_opts {
/* cvd parameters */
enum cvd_mode mode; /* CVD mode: 0 - NONE, 1 - 3 sliders, 2 - 1 slider*/
MATFLOAT gain[3]; /* Compensation Gain: ([0] - Protanopia, [1] - Deuteranopia, [2] - Tritanopia: [0.0,2.0]=0.0 */
struct s_cs_opts cs_opts; /* Color Space parameters */
/* 3DLUT parameters */
int en_merge_3dlut;
int num_pnts_3dlut;
int bitwidth_3dlut;
unsigned short *ptr_3dlut_rgb;
};
void cvd_api_set_def(struct s_cvd_api_opts *ptr_api_cvd_opts);
int cvd_api_gen_map(struct s_cvd_api_opts *ptr_api_cvd_opts, struct s_cvd_map *ptr_cvd_map);
int cvd_api_gen_3dlut(struct s_cvd_api_opts *ptr_api_cvd_opts, struct s_cvd_map *ptr_cvd_map);
#ifdef __cplusplus
}
#endif

132
src/amd/gmlib/gm/cvd_funcs.c Executable file
View file

@ -0,0 +1,132 @@
/*
* Copyright 2025 Advanced Micro Devices, Inc.
* SPDX-License-Identifier: MIT
*
*----------------------------------------------------------------------
* File Name : cvd_funcs.c
* Purpose : Color Vision Deficiency functions
* Author : Vladimir Lachine (vlachine@amd.com)
* Date : January 21, 2020
* Version : 1.0
*----------------------------------------------------------------------
*
*/
#ifndef GM_SIM
#pragma code_seg("PAGED3PC")
#pragma data_seg("PAGED3PD")
#pragma const_seg("PAGED3PR")
#endif
#include "cvd_funcs.h"
void cvd_ctor(struct s_cvd_map *ptr_cvd_map)
{
cvd_set_def(ptr_cvd_map);
}
void cvd_dtor(struct s_cvd_map *ptr_cvd_map)
{
cvd_set_def(ptr_cvd_map);
}
void cvd_set_def(struct s_cvd_map *ptr_cvd_map)
{
int nk;
ptr_cvd_map->mode = ECM_NONE;
for (nk = 0; nk < 3; nk++)
ptr_cvd_map->gain[nk] = 0.0;
}
int cvd_rgb_to_rgb(struct s_cvd_map *ptr_cvd_map, MATFLOAT rgb_inp[3], MATFLOAT rgb_out[3])
{
int rc = 0;
if (ptr_cvd_map->mode != ECM_NONE)
rc = cvd_rgb_to_rgb_dalton(ptr_cvd_map, rgb_inp, rgb_out);
else
mat_copy(rgb_inp, rgb_out, 3);
return rc;
}
void cvd_model_rgb(struct s_color_space *ptr_color_space, MATFLOAT rgb_inp[3], MATFLOAT rgb_out[3],
enum cvd_type type)
{
static MATFLOAT cvd_mat_rgb2lms[3][3] = {
{17.8824, 43.5161, 4.11935},
{3.45565, 27.1554, 3.86714},
{0.0299566, 0.184309, 1.46709}
};
static MATFLOAT cvd_mat_lms2rgb[3][3] = {
{ 0.080944, -0.130504, 0.116721},
{-0.0102485, 0.0540194, -0.113615},
{-0.000365294, -0.00412163, 0.693513}
};
static MATFLOAT cvd_mat_model[ECVDT_NUM][3][3] = {
{/* protanopia */ {0.0, 2.02324, -2.52581}, {0.0, 1.0, 0.0}, {0.0, 0.0, 1.0}},
{/* deuteranopia */ {1.0, 0.0, 0.0}, {0.494207, 0.0, 1.24827}, {0.0, 0.0, 1.0}},
// {/* tritanopia */ {1.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {-0.395913, 0.801109, 0.0}}
{/* tritanopia */ {1.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {-0.012245, 0.0720345, 0.0}}
};
MATFLOAT lms_inp[3], lms_out[3];
mat_eval_3x3(cvd_mat_rgb2lms, rgb_inp, lms_inp);
mat_eval_3x3(cvd_mat_model[type], lms_inp, lms_out);
mat_eval_3x3(cvd_mat_lms2rgb, lms_out, rgb_out);
cs_clamp_rgb(rgb_out, 0.0, 1.0);
}
int cvd_rgb_to_rgb_dalton(struct s_cvd_map *ptr_cvd_map, MATFLOAT rgb_inp[3], MATFLOAT rgb_out[3])
{
static MATFLOAT cvd_mat_err[ECVDT_NUM][3][3] = {
{/* protanopia */ {-0.5, 0.0, 0.0}, {1.0, 1.0, 0.0}, {1.0, 0.0, 1.0}},
{/* deuteranopia */ { 1.0, 1.0, 0.0}, {0.0, -0.5, 0.0}, {0.0, 1.0, 1.0}},
{/* tritanopia */ { 1.0, 0.0, 1.0}, {0.0, 1.0, 1.0}, {0.0, 0.0, -0.5}}
};
MATFLOAT rgb_inp_lin[3], rgb_out_lin[3];
MATFLOAT rgb_err_map[ECVDT_NUM][3];
MATFLOAT err_map;
MATFLOAT gain;
int nc, nk;
cs_gamma_rgb(rgb_inp, rgb_inp_lin, ptr_cvd_map->color_space.gamma_parm, EGD_NONLIN_2_LIN);
mat_copy(rgb_inp_lin, rgb_out_lin, 3);
for (nk = 0; nk < 3; nk++) {
MATFLOAT rgb_cvd[3], rgb_err[3];
cvd_model_rgb(&ptr_cvd_map->color_space, rgb_inp_lin, rgb_cvd, nk);
for (nc = 0; nc < 3; nc++)
rgb_err[nc] = rgb_inp_lin[nc] - rgb_cvd[nc];
mat_eval_3x3(cvd_mat_err[nk], rgb_err, rgb_err_map[nk]);
}
if (ptr_cvd_map->mode == ECM_DALTON_SLD3) { /* ECM_DALTON_SLD3 */
for (nk = 0; nk < 3; nk++) {
gain = ptr_cvd_map->gain[nk] * 0.5;
for (nc = 0; nc < 3; nc++)
rgb_out_lin[nc] += rgb_err_map[nk][nc] * gain;
}
} else { /* ECM_DALTON_SLD1 */
for (nc = 0; nc < 3; nc++) {
if (ptr_cvd_map->gain[0] <= 1.0)
err_map = ptr_cvd_map->gain[0] * rgb_err_map[0][nc];
else if (ptr_cvd_map->gain[0] <= 2.0)
err_map = rgb_err_map[0][nc] + (ptr_cvd_map->gain[0] - 1.0) * (rgb_err_map[1][nc] - rgb_err_map[0][nc]);
else
err_map = rgb_err_map[1][nc] + (ptr_cvd_map->gain[0] - 2.0) * (rgb_err_map[2][nc] - rgb_err_map[1][nc]);
rgb_out_lin[nc] += err_map;
}
}
cs_clamp_rgb(rgb_out_lin, 0.0, 1.0);
cs_gamma_rgb(rgb_out_lin, rgb_out, ptr_cvd_map->color_space.gamma_parm, EGD_LIN_2_NONLIN);
return 0;
}

57
src/amd/gmlib/gm/cvd_funcs.h Executable file
View file

@ -0,0 +1,57 @@
/*
* Copyright 2025 Advanced Micro Devices, Inc.
* SPDX-License-Identifier: MIT
*
*----------------------------------------------------------------------
* File Name : cvd_funcs.h
* Purpose : Color Vision Deficiency functions
* Author : Vladimir Lachine (vlachine@amd.com)
* Date : January 21, 2020
* Version : 1.0
*----------------------------------------------------------------------
*
*/
#pragma once
#include "cs_funcs.h"
#ifdef __cplusplus
extern "C" {
#endif
enum cvd_mode {
ECM_NONE = 0, /* NONE */
ECM_DALTON_SLD3 = 1, /* DALTONIZATION 3 control sliders */
ECM_DALTON_SLD1 = 2, /* DALTONIZATION 1 control slider */
ECM_NUM = 3
};
enum cvd_type {
ECVDT_PROTANOPIA = 0, /* protanopia */
ECVDT_DEUTERANOPIA = 1, /* deuteranopia */
ECVDT_TRITANOPIA = 2, /* tritanopia */
ECVDT_NUM = 3
};
struct s_cvd_map {
/* input parameters */
enum cvd_mode mode; /* Enable/disable CVD: {0,1,2}=0 */
MATFLOAT gain[3]; /* Compensation Gain: ([0] - Protanopia, [1] - Deuteranopia, [2] - Tritanopia: [0.0,2.0]=0.0 */
struct s_color_space color_space; /* Color Space (primary RGBW chromaticity, gamma, and Luminance min/max) */
};
/* constructor and destructor */
void cvd_ctor(struct s_cvd_map *ptr_cvd_map);
void cvd_dtor(struct s_cvd_map *ptr_cvd_map);
void cvd_set_def(struct s_cvd_map *ptr_cvd_map);
int cvd_rgb_to_rgb(struct s_cvd_map *ptr_cvd_map, MATFLOAT rgb_inp[3], MATFLOAT rgb_out[3]);
void cvd_model_rgb(struct s_color_space *ptr_color_space, MATFLOAT rgb_inp[3], MATFLOAT rgb_out[3],
enum cvd_type type);
int cvd_rgb_to_rgb_dalton(struct s_cvd_map *ptr_cvd_map, MATFLOAT rgb_inp[3], MATFLOAT rgb_out[3]);
#ifdef __cplusplus
}
#endif

194
src/amd/gmlib/gm/gm_api_funcs.c Executable file
View file

@ -0,0 +1,194 @@
/*
* Copyright 2025 Advanced Micro Devices, Inc.
* SPDX-License-Identifier: MIT
*
*----------------------------------------------------------------------
* File Name : gm_api_funcs.c
* Purpose : Gamut Mapping API functions
* Author : Vladimir Lachine (vlachine@amd.com)
* Date : November 12, 2024
* Version : 3.1
*----------------------------------------------------------------------
*
*/
#ifndef GM_SIM
#pragma code_seg("PAGED3PC")
#pragma data_seg("PAGED3PD")
#pragma const_seg("PAGED3PR")
#endif
#include "gm_api_funcs.h"
/* non library helper functions */
/*
// SESSION START
struct s_gamut_map gamut_map;
gm_ctor(&gamut_map, gm_api_alloc, gm_api_free); // constructor - once per session
struct s_gm_opts gm_opts;
gm_api_set_def(&gm_opts); // set default mapping
gm_api_gen_map(&gm_opts, &gamut_map); // generate default mapping
gm_opts.ptr_3dlut_rgb = (unsigned short *)gamut_map.ptr_func_alloc(
3 * sizeof(unsigned short) * gm_opts.num_pnts_3dlut * gm_opts.num_pnts_3dlut * gm_opts.num_pnts_3dlut); // allocate 3DLUT memory
SOURCE OR TARGET GAMUT IS CHANGED EVENT
{
// ...................
// set parameters of src gamut, dst gamut and gamut mapping
// ...................
gm_opts.update_msk = GM_UPDATE_SRC; // GM_UPDATE_SRC -
update source gamut, GM_UPDATE_DST - update destination gamut or mapping parameters has been changed
// or
gm_opts.update_msk = GM_UPDATE_DST; // GM_UPDATE_SRC - u
pdate source gamut, GM_UPDATE_DST - update destination gamut or mapping parameters has been changed
int rc = gm_api_gen_map(&gm_opts, &gamut_map);
if (rc == 0) {
rc = gm_api_gen_3dlut(&gm_opts, &gamut_map); // generate 3DLUT
// .................
// load 3DLUT to HW registers
// .................
}
}
// SESSION END
gamut_map.ptr_func_free(gm_opts.ptr_3dlut_rgb); // free 3DLUT memory
gm_dtor(&gamut_map); // destructor - once per session
*/
int gm_api_gen_map(struct s_gm_opts *ptr_gm_opts, struct s_gamut_map *ptr_gamut_map)
{
int rc;
/* initialize gamut mapping staructure from api gamut options */
if (ptr_gm_opts->update_msk & GM_UPDATE_DST)
gm_api_init(ptr_gm_opts, ptr_gamut_map);
/* init src and dst gamuts */
rc = gm_init_gamuts(ptr_gamut_map, &ptr_gm_opts->cs_opts_src, &ptr_gm_opts->cs_opts_dst,
ptr_gm_opts->mode, ptr_gm_opts->update_msk);
/* generate gamut edge and other internal data */
if (rc == 0)
gm_gen_map(ptr_gamut_map, ptr_gm_opts->update_msk);
ptr_gm_opts->update_msk = 0;
return rc;
}
int gm_api_gen_3dlut(struct s_gm_opts *ptr_gm_opts, struct s_gamut_map *ptr_gamut_map)
{
if (ptr_gm_opts->ptr_3dlut_rgb) {
gm_gen_3dlut(ptr_gamut_map, ptr_gm_opts->num_pnts_3dlut,
ptr_gm_opts->bitwidth_3dlut, ptr_gm_opts->en_merge_3dlut, ptr_gm_opts->ptr_3dlut_rgb);
return 0;
}
return -1; /* something wrong */
}
void gm_api_set_def(struct s_gm_opts *ptr_gm_opts)
{
int nk;
ptr_gm_opts->gamut_map_mode = EGMM_NONE;
ptr_gm_opts->en_tm_scale_color = 1;
ptr_gm_opts->hue_rot_mode = EHRM_NONE;
ptr_gm_opts->mode = 0;
ptr_gm_opts->step_samp = 0.0005;
ptr_gm_opts->map_type = EMT_SEG;
ptr_gm_opts->num_hue_pnts = 180;
ptr_gm_opts->num_edge_pnts = 121;
ptr_gm_opts->num_int_pnts = 33;
ptr_gm_opts->org2_perc_c = GM_ORG2_PERC;
for (nk = 0; nk < GM_NUM_PRIM; nk++) {
ptr_gm_opts->vec_org1_factor[nk] = gm_vec_org13_factor_def[nk][0];
ptr_gm_opts->vec_org3_factor[nk] = gm_vec_org13_factor_def[nk][1];
}
ptr_gm_opts->reserve = 0;
ptr_gm_opts->show_pix_mode = ESPM_NONE;
for (nk = 0; nk < 2; nk++)
ptr_gm_opts->show_pix_hue_limits[nk] = 0.0;
cs_set_opts_def(&ptr_gm_opts->cs_opts_src);
cs_set_opts_def(&ptr_gm_opts->cs_opts_dst);
ptr_gm_opts->update_msk = GM_UPDATE_SRC | GM_UPDATE_DST;
ptr_gm_opts->en_merge_3dlut = 0;
ptr_gm_opts->num_pnts_3dlut = 17;
ptr_gm_opts->bitwidth_3dlut = 12;
}
void gm_api_init(struct s_gm_opts *ptr_gm_opts, struct s_gamut_map *ptr_gamut_map)
{
int nk;
gm_set_def(ptr_gamut_map);
ptr_gamut_map->gamut_map_mode = ptr_gm_opts->gamut_map_mode;
ptr_gamut_map->en_tm_scale_color = ptr_gm_opts->en_tm_scale_color;
ptr_gamut_map->hue_rot_mode = ptr_gm_opts->hue_rot_mode;
ptr_gamut_map->mode = ptr_gm_opts->mode;
ptr_gamut_map->org2_perc_c = ptr_gm_opts->org2_perc_c;
for (nk = 0; nk < GM_NUM_PRIM; nk++) {
/* Factor of Origin1 for M,R,Y,G,C,B = 1.3, 1.3, 1.3, 1.3, 1.2, 1.0 */
ptr_gamut_map->vec_org1_factor[nk] = ptr_gm_opts->vec_org1_factor[nk];
/* Factor of Origin3 for M,R,Y,G,C,B = 1.05, 1.1, 1.1, 1.05, 1.01, 1.06 */
ptr_gamut_map->vec_org3_factor[nk] = ptr_gm_opts->vec_org3_factor[nk];
}
ptr_gamut_map->step_samp = ptr_gm_opts->step_samp; /* default is 0.0005 */
ptr_gamut_map->map_type = ptr_gm_opts->map_type; /* default is EMT_SEG */
ptr_gamut_map->num_hue_pnts = ptr_gm_opts->num_hue_pnts; /* default is 181 */
ptr_gamut_map->num_edge_pnts = ptr_gm_opts->num_edge_pnts; /* default is 121 */
ptr_gamut_map->num_int_pnts = ptr_gm_opts->num_int_pnts; /* default is 33 */
ptr_gamut_map->reserve = ptr_gm_opts->reserve;
ptr_gamut_map->show_pix_mode = ptr_gm_opts->show_pix_mode;
for (nk = 0; nk < 2; nk++)
ptr_gamut_map->show_pix_hue_limits[nk] = ptr_gm_opts->show_pix_hue_limits[nk];
}
#ifndef GM_SIM
#ifndef LINUX_DM
#include "dm_services.h"
#else
/* TBD: include for LINUX_DM */
#endif /* LINUX_DM */
#else
#include <stdlib.h>
#endif /* GM_SIM */
void *gm_api_alloc(unsigned int size_bytes, void* mem_ctx)
{
#ifndef GM_SIM
#ifndef LINUX_DM
return dm_alloc(size_bytes);
#else
/* TBD: alloc() for LINUX_DM */
#endif /* LINUX_DM */
#else
return malloc(size_bytes);
#endif /* GM_SIM */
}
void gm_api_free(void *ptr_mem, void* mem_ctx)
{
#ifndef GM_SIM
#ifndef LINUX_DM
dm_free(ptr_mem);
#else
/* TBD: free() for LINUX_DM */
#endif /* LINUX_DM */
#else
free(ptr_mem);
#endif /* GM_SIM */
}

79
src/amd/gmlib/gm/gm_api_funcs.h Executable file
View file

@ -0,0 +1,79 @@
/*
* Copyright 2025 Advanced Micro Devices, Inc.
* SPDX-License-Identifier: MIT
*
*----------------------------------------------------------------------
* File Name : gm_api_funcs.h
* Purpose : Gamut Mapping API functions
* Author : Vladimir Lachine (vlachine@amd.com)
* Date : November 12, 2024
* Version : 3.1
*----------------------------------------------------------------------
*
*/
#pragma once
#include "gm_funcs.h"
#ifdef __cplusplus
extern "C" {
#endif
struct s_gm_opts {
enum gm_gamut_map_mode gamut_map_mode;
/* Gamut Map Mode: 0 - no gamut map, 1 - Tone Map BT2390-4, 2 - TM+CHTO, 3 - TM+CHSO, 4 - TM+CHCI */
enum gm_hue_rot_mode hue_rot_mode;
/* Hue Rotation Mode: 0 - none, 1 - hue rotation, 2 - chroma compression, 3 - hue rotation and chroma compression */
int en_tm_scale_color;
/* Enable/Disable Color Scaling (valid for Tone Mapping mode only): {0,1} = 1 */
unsigned int mode;
/* mode = 0 : Reserved for modifications of the Gamut Map algo */
/* CHTO tuning parameters */
MATFLOAT org2_perc_c;
/* Origin2 percentage gap for chroma [0.7,095] = 0.9 */
MATFLOAT vec_org1_factor[GM_NUM_PRIM];
/* Factor of Origin1 for M,R,Y,G,C,B [1.0,1.4] = 1.3, 1.3, 1.3, 1.3, 1.2, 1.0 */
MATFLOAT vec_org3_factor[GM_NUM_PRIM];
/* Factor of Origin3 for M,R,Y,G,C,B [1.01,1,2] = 1.05, 1.2, 1.05, 1.05, 1.01, 1.05 */
MATFLOAT step_samp;
/* Sampling precision in IC space for edge search [0.00001,0.001]=0.0001 */
enum gm_map_type map_type;
/* Map type: {0,1,2} = 0 : 0 - segments intersection SEG, 1 - radius sampling RAD, 2 hybrid - SEG+RAD */
int num_hue_pnts;
/* Number of hue grid points: [90,360]=360 */
int num_edge_pnts;
/* Number of edge IC grid points: [91, 181] = 181 */
int num_int_pnts;
/* Number of intensity grid points for primary hues: [5,33] = 33 */
/* show pixel parameters */
int reserve;
/* Reserved for debugging purpose = 0 */
enum gm_show_pix_mode show_pix_mode;
/* EShowPixMode: [0,8]=0 : show pixel debugging mode */
MATFLOAT show_pix_hue_limits[2];
/* Show Pixel mode hue ranges */
/* color space parameters */
struct s_cs_opts cs_opts_src;
struct s_cs_opts cs_opts_dst;
int update_msk;
/* Update mask: GM_UPDATE_SRC - update source gamut, GM_UPDATE_DST - update destination gamut */
/* 3DLUT parameters */
int en_merge_3dlut;
int num_pnts_3dlut;
int bitwidth_3dlut;
unsigned short *ptr_3dlut_rgb;
};
int gm_api_gen_map(struct s_gm_opts *ptr_gm_opts, struct s_gamut_map *ptr_gamut_map);
int gm_api_gen_3dlut(struct s_gm_opts *ptr_gm_opts, struct s_gamut_map *ptr_gamut_map);
void gm_api_set_def(struct s_gm_opts *ptr_gm_opts);
void gm_api_init(struct s_gm_opts *ptr_gm_opts, struct s_gamut_map *ptr_gamut_map);
void *gm_api_alloc(unsigned int size_bytes, void* mem_ctx); /* alloc array */
void gm_api_free(void *ptr_mem, void* mem_ctx); /* free array */
#ifdef __cplusplus
}
#endif

1492
src/amd/gmlib/gm/gm_funcs.c Executable file

File diff suppressed because it is too large Load diff

299
src/amd/gmlib/gm/gm_funcs.h Executable file
View file

@ -0,0 +1,299 @@
/*
* Copyright 2025 Advanced Micro Devices, Inc.
* SPDX-License-Identifier: MIT
*
*----------------------------------------------------------------------
* File Name : gm_funcs.h
* Purpose : Gamut Mapping functions
* Author : Vladimir Lachine (vlachine@amd.com)
* Date : November 11, 2024
* Version : 3.1
*----------------------------------------------------------------------
*
*/
#pragma once
#include "mat_funcs.h"
#include "cs_funcs.h"
#ifdef __cplusplus
extern "C" {
#endif
#define GM_NUM_PRIM 6 /* number of primary/secondary colors */
#define GM_NUM_HUE 360 /* default number of hue slices in edge description grid */
#define GM_NUM_EDGE 181 /* default number of egde points per hue in edge description grid */
#define GM_NUM_INT 33 /* default number of intensity levels in HueRot grid */
#define GM_STEP_SAMP 0.0001 /* default accuracy of edge detection procedures (for 14 bits signal) */
#define GM_EDGE_ORG 0.5 /* default center point for edge description procedure */
#define GM_ORG1_FACTOR 0.5 /* Origin1 default intensity */
#define GM_ORG3_FACTOR 1.0 /* Origin3 default intensity */
#define GM_ORG2_PERC 0.9
#define GM_CUSP_ADJUST 0x01 /* Adjust cusp points */
#define GM_ZONE1_FLEX 0x02 /* Flexible zone 1 */
#define GM_PQTAB_3DLUT 0x04
#define GM_PQTAB_GBD 0x08
#define GM_SCALE_LUMA 0x04 /* Luma scaling */
#define GM_UPDATE_SRC 0x01
#define GM_UPDATE_DST 0x02
#define GM_HUE_SHIFT 0x01
#define GM_CHROMA_GAIN 0x02
#define GM_PQTAB_NUMPNTS 4097
enum gm_gamut_map_mode {
EGMM_NONE = 0, /* NONE */
EGMM_TM = 1, /* Tone Map (BT2390-4) */
EGMM_TM_CHTO = 2, /* Tone Map + CHTO (Constant Hue Triple Origin */
EGMM_TM_CHSO = 3, /* Tone Map + CHSO (Constant Hue Single Origin */
EGMM_TM_CHCI = 4 /* Tone Map + CHCI (Constant Hue Constant Intensity) */
};
enum gm_hue_rot_mode {
EHRM_NONE = 0, /* NONE */
EHRM_HR = 1, /* Hue rotation */
EHRM_CC = 2, /* Chroma compression */
EHRM_HR_CC = 3 /* Hue rotation + Chroma compression */
};
enum gm_map_type {
EMT_SEG = 0, /* intensity segment */
EMT_RAD = 1, /* arc segment */
EMT_SEGRAD = 2 /* hybrid */
};
enum gm_edge_type {
EET_RAD = 0, /* elevation angle uniform */
EET_CHROMA = 1 /* intensity uniform */
};
enum gm_show_pix_mode {
ESPM_NONE = 0, /* NONE */
ESPM_NOMAP = 1, /* Show pixels inside gamut */
ESPM_MAP = 2, /* Show pixels outside gamut */
ESPM_MAPZ1 = 3, /* Show pixels outside gamut in zone1 */
ESPM_MAPZ2 = 4, /* Show pixels outside gamut in zone2 */
ESPM_MAPZ3 = 5, /* Show pixels outside gamut in zone3 */
ESPM_NUMZ = 6, /* Show pixels zone number */
ESPM_HUEINP = 7, /* Show input pixels with hue in range */
ESPM_HUEOUT = 8 /* Show output pixels with hue in range */
};
struct s_gamut_map {
/* input parameters */
enum gm_gamut_map_mode gamut_map_mode;
/* Gamut Map Mode: 0 - no gamut map, 1 - Tone Map BT2390-4, 2 - TM+CHTO, 3 - TM+CHSO, 4 - TM+CHCI */
enum gm_hue_rot_mode hue_rot_mode;
/* Hue Rotation Mode: 0 - none, 1 - hue rotation, 2 - chroma compression, 3 - hue rotation and chroma compression */
int en_tm_scale_color;
/* Enable/Disable Color Scaling in Tone Mapping mode only: {0,1} = 1 */
unsigned int mode;
/* Reserved for modifications of the Gamut Map algo */
struct s_color_space color_space_src;
/* Source color space (primary RGBW chromaticity, gamma, and Luminance min/max) */
struct s_color_space color_space_dst;
/* Destination color space (primary RGBW chromaticity, gamma and Luminance min/max) */
/* CHTO input tuning parameters */
MATFLOAT org2_perc_c;
/* Origin2 percentage gap for chroma [0.0,1.0] = 0.9 */
MATFLOAT vec_org1_factor[GM_NUM_PRIM];
/* Factor of Origin1 for M,R,Y,G,C,B [0.0,2.0] = 1.3, 1.3, 1.3, 1.3, 1.2, 1.0 */
MATFLOAT vec_org3_factor[GM_NUM_PRIM];
/* Factor of Origin3 for M,R,Y,G,C,B [1.0,1.5] = 1.05, 1.2, 1.05, 1.05, 1.01, 1.05 */
/* GM input tuning parameters */
int num_hue_pnts;
/* Number of hue grid points: [90,360]=360 */
int num_edge_pnts;
/* Number of edge IC grid points: [91, 181] = 181 */
int num_int_pnts;
/* Number of intensity grid points for primary hues: [5,33] = 33 */
enum gm_edge_type edge_type;/* Edge type: {0,1} = 0 : 0 - radius based EET_RAD, 1 - chroma based EET_CHROMA */
enum gm_map_type map_type;
/* Map type: {0,1,2} = 0 : 0 - segments intersection SEG, 1 - radius sampling RAD, 2 hybrid - SEG+RAD */
MATFLOAT step_samp;
/* Sampling precision in IC space for edge search [0.00001,0.001]=0.0001 */
int reserve;
/* Reserved for debugging purpose */
enum gm_show_pix_mode show_pix_mode;
/* SHow Pix Mode: [0,8]=0 : show pixel debugging mode */
MATFLOAT show_pix_hue_limits[2]; /* Show Pixel mode hue ranges */
/* calculated variables */
MATFLOAT lum_min;
/* minLum (BT2390-4) in PQ non-linear space */
MATFLOAT lum_max;
/* maxLum (BT2390-4) in PQ non-linear space */
MATFLOAT vec_prim_src_ich[3 * GM_NUM_PRIM];
/* ich for M,R,Y,G,C,B primaries of source gamut */
MATFLOAT vec_prim_dst_ich[3 * GM_NUM_PRIM];
/* ich for M,R,Y,G,C,B primaries of target gamut */
MATFLOAT *ptr_cusp_src_ic;
/* Intensity and chroma of Cusp num_hue_pnts points for source gamut */
MATFLOAT *ptr_cusp_dst_ic;
/* Intensity and chroma of Cusp num_hue_pnts points for target gamut */
MATFLOAT *ptr_org2_ic;
/* Intensity and chroma of Origin2 for num_hue_pnts points */
MATFLOAT *ptr_org3_ic;
/* Intensity and chroma of Origin3 for num_hue_pnts points */
MATFLOAT *ptr_hr_src_hc;
/* Source Primary Hue and Chroma for (GM_NUM_PRIM * num_int_pnts) points */
MATFLOAT *ptr_hr_dst_hc;
/* Target Primary Hue and Chroma for (GM_NUM_PRIM * num_int_pnts) points */
MATFLOAT *ptr_edge_ic;
/* Target gamut edge for (num_hue_pnts * num_edge_pnts) points */
void *(*ptr_func_alloc)(unsigned int, void*);
/* allocate memory function */
void (*ptr_func_free)(void*, void*);
/* deallocate memory function */
void* memory_context;
/*memory management context*/
MATFLOAT hue_max;
MATFLOAT org1;
MATFLOAT org3;
/* internally calculated constant */
};
void gm_ctor(struct s_gamut_map *ptr_gamut_map,
void*(*ptr_func_alloc)(unsigned int, void*),
void(*ptr_func_free)(void*, void*),
void* mem_context); /* constructor */
void gm_dtor(struct s_gamut_map *ptr_gamut_map); /* destructor */
void gm_alloc_mem(struct s_gamut_map *ptr_gamut_map);
void gm_free_mem(struct s_gamut_map *ptr_gamut_map);
/* initialization functions */
void gm_set_def(struct s_gamut_map *gamut_map);
int gm_init_gamuts(struct s_gamut_map *ptr_gamut_map, struct s_cs_opts *ptr_cs_opts_src,
struct s_cs_opts *ptr_cs_opts_dst, unsigned int gm_mode, int update_msk);
int gm_check_gamut(struct s_gamut_map *ptr_gamut_map);
void gm_gencusp_ic(struct s_gamut_map *ptr_gamut_map, int color_space); /* color_space : 0 - source, 1 - target */
/* gamut map description generation functions */
void gm_gen_edge_hue(struct s_gamut_map* ptr_gamut_map, int hue_ind);
/* resampling functions */
void gm_resample_hc(MATFLOAT vec_ich_inp[][3], MATFLOAT *ptr_hc_out,
int num_int_pnts_src, int num_int_pnts_dst);
void gm_resample_hue_ic(MATFLOAT *ptr_hue, MATFLOAT *ptr_ic_inp,
MATFLOAT *ptr_ic_out, int num_hue_pnts_inp, int num_hue_pnts_out);
void gm_genprim_hc(struct s_color_space *ptr_color_space, MATFLOAT *ptr_hr_hc,
int num_int_pnts, MATFLOAT luma_limits[3], MATFLOAT lum_min, MATFLOAT lum_max);
/* Origin2 and Origin3 generation functions */
void gm_genorg13_factor(struct s_gamut_map* ptr_gamut_map, MATFLOAT* ptr_org13_factor);
void gm_genorigin23_hue(struct s_gamut_map* ptr_gamut_map, MATFLOAT* ptr_org13_factor, int hue_ind);
void gm_getorigin23(struct s_color_space* ptr_color_space_src, struct s_color_space* ptr_color_space_dst,
MATFLOAT hue, MATFLOAT org_13_factor[2], MATFLOAT org2_perc_c,MATFLOAT cusp_ic_src[2],
MATFLOAT cusp_ic_dst[2], MATFLOAT origin2_ic[2], MATFLOAT origin3_ic[2], int en_pq_lut);
/* gamut map functions */
int gm_rgb_to_rgb(struct s_gamut_map *ptr_gamut_map, MATFLOAT rgb_inp[3], MATFLOAT rgb_out[3]);
MATFLOAT gm_tm_itp(MATFLOAT itp_inp[3], MATFLOAT itp_out[3], MATFLOAT luma_limits[3],
MATFLOAT lum_min, MATFLOAT lum_max, int en_tm_scale_color, int en_tm_scale_luma);
MATFLOAT gm_tm_luma(MATFLOAT luma, MATFLOAT luma_limits[3], MATFLOAT lum_min, MATFLOAT lum_max);
MATFLOAT gm_scale_luma(MATFLOAT luma, MATFLOAT luma_limits[3], MATFLOAT lum_min, MATFLOAT lum_max);
int gm_map_itp(struct s_gamut_map *ptr_gamut_map, MATFLOAT itp_inp[3], MATFLOAT itp_out[3]);
int gm_map_chto_itp(struct s_gamut_map *ptr_gamut_map, MATFLOAT itp_inp[3], MATFLOAT itp_out[3]);
int gm_map_chso_itp(struct s_gamut_map *ptr_gamut_map, MATFLOAT itp_inp[3], MATFLOAT itp_out[3]);
int gm_map_chci_itp(struct s_gamut_map *ptr_gamut_map, MATFLOAT itp_inp[3], MATFLOAT itp_out[3]);
/* hue rotation functions */
void gm_hr_itp(struct s_gamut_map *gamut_map, MATFLOAT itp_inp[3], MATFLOAT itp_out[3], int direction);
void gm_hr_ich(struct s_gamut_map *ptr_gamut_map, MATFLOAT ich_inp[3], MATFLOAT ich_out[3], int direction);
void gm_get_hr_parms(MATFLOAT ich[3], MATFLOAT luma_limits[3], MATFLOAT *ptr_hr_src_hc,
MATFLOAT *ptr_hr_dst_hc, int num_int_pnts, MATFLOAT rot_hs_cg[2]);
/* segments intersection functions */
int gm_map_seg_itp(struct s_gamut_map *ptr_gamut_map, MATFLOAT itp_inp[3],
MATFLOAT itp_out[3], int zone, MATFLOAT origin2_ic[2], MATFLOAT origin3_ic[2], int vec_hue_ind[2], MATFLOAT hue_phs);
int gm_map_rad_itp(struct s_gamut_map *ptr_gamut_map, MATFLOAT itp_inp[3],
MATFLOAT itp_out[3], int zone, MATFLOAT origin2_ic[2], MATFLOAT origin3_ic[2], MATFLOAT hue);
int gm_map_segrad_itp(struct s_gamut_map *ptr_gamut_map, MATFLOAT itp_inp[3],
MATFLOAT itp_out[3], int zone, MATFLOAT origin2_ic[2],
MATFLOAT origin3_ic[2], MATFLOAT hue, int vec_hue_ind[2], MATFLOAT hue_phs);
/* interpolate Ic between two hues */
MATFLOAT gm_hue_to_index_phase(MATFLOAT hue, MATFLOAT hue_max, int num_hue_pnts, int vec_hue_ind[2]);
void gm_interp_ic(int vec_hue_ind[2], MATFLOAT hue_phs,
MATFLOAT vec_pnt_ic[], MATFLOAT pnt_ic[2]);
void gm_getseg_ic(int vec_hue_ind[2], MATFLOAT hue_phs,
int ind, int num_edge_pnts, MATFLOAT *ptr_edge_ic, MATFLOAT pnt_ic[2]);
/* Edge generation functions */
void gm_genedge(struct s_color_space *ptr_color_space, MATFLOAT luma_limits[3],
int num_edge_pnts, enum gm_edge_type edge_type, MATFLOAT step_samp, MATFLOAT hue,
MATFLOAT *ptr_edge_ic, int en_pq_lut);
void gm_genedge_int(struct s_color_space *ptr_color_space, MATFLOAT luma_limits[3],
int num_edge_pnts, MATFLOAT hue, MATFLOAT step_samp, MATFLOAT *ptr_edge_ic,
int en_pq_lut);
void gm_genedge_rad(struct s_color_space *ptr_color_space, MATFLOAT luma_limits[3],
int num_edge_pnts, MATFLOAT hue, MATFLOAT step_samp, MATFLOAT *ptr_edge_ic,
int en_pq_lut);
void gm_sample_edge_ic(struct s_color_space *ptr_color_space,
MATFLOAT hue_cos_sin[2], MATFLOAT inc_ic[2], MATFLOAT pnt_ic[2],
int en_pq_lut);
void gm_edgecusp_adjust(MATFLOAT *ptr_edge_ic, int num_edge_pnts, MATFLOAT cusp_ic[2]);
/* Gamut Map related functions */
int gm_get_zone(MATFLOAT itp[3], MATFLOAT origin2_ic[2], MATFLOAT origin3_ic[2], MATFLOAT luma_limits[3]);
int gm_map_zone1_seg(MATFLOAT itp_inp[3], MATFLOAT itp_out[3], int vec_hue_ind[2],
MATFLOAT hue_phs, MATFLOAT origin2_ic[2], int num_edge_pnts, MATFLOAT *ptr_edge_ic, int pnt_map, int pnt_inc);
int gm_map_zone2_seg(MATFLOAT itp_inp[3], MATFLOAT itp_out[3], int vec_hue_ind[2],
MATFLOAT hue_phs, MATFLOAT origin2_ic[2], int num_edge_pnts, MATFLOAT *ptr_edge_ic, int pnt_map, int pnt_inc);
int gm_map_zone3_seg(MATFLOAT itp_inp[3], MATFLOAT itp_out[3], int vec_hue_ind[2],
MATFLOAT hue_phs, MATFLOAT origin3_ic[2], int num_edge_pnts, MATFLOAT *ptr_edge_ic, int pnt_map, int pnt_inc);
void gm_map_zone1_rad(struct s_color_space *ptr_color_space, MATFLOAT itp_inp[3],
MATFLOAT itp_out[3], MATFLOAT step_samp, MATFLOAT origin2_ic[2], MATFLOAT hue, int num_itr);
void gm_map_zone2_rad(struct s_color_space *ptr_color_space, MATFLOAT itp_inp[3],
MATFLOAT itp_out[3], MATFLOAT step_samp, MATFLOAT origin2_ic[2], MATFLOAT hue, int num_itr);
void gm_map_zone3_rad(struct s_color_space *ptr_color_space, MATFLOAT itp_inp[3],
MATFLOAT itp_out[3], MATFLOAT step_samp, MATFLOAT origin3_ic[2], MATFLOAT hue, int num_itr);
/* Show Pixel debugging functions */
void gm_show_pix(int zone, MATFLOAT itp_src[3], MATFLOAT itp_dst[3],
MATFLOAT rgb[3], enum gm_show_pix_mode show_pix_mode, MATFLOAT hue_limits[2]);
void gm_rgb_to_itp(struct s_color_space* ptr_color_space, MATFLOAT rgb_inp[3], MATFLOAT itp_out[3], int en_pq_lut);
void gm_itp_to_rgb(struct s_color_space* ptr_color_space, MATFLOAT itp_inp[3], MATFLOAT rgb_out[3], int en_pq_lut);
int gm_is_valid_itp(struct s_color_space* ptr_color_space, MATFLOAT itp[3], int en_pq_lut);
int gm_is_valid_ic(struct s_color_space* ptr_color_space, MATFLOAT pnt_ic[2], MATFLOAT hue_sin_cos[2], int en_pq_lut);
void gm_gen_pq_lut(float* ptr_lut, int num_pnts, enum cs_gamma_dir gamma_dir);
MATFLOAT gm_pq_lut(MATFLOAT val, enum cs_gamma_dir gamma_dir);
int gm_seg_intersection(MATFLOAT p0_xy[2], MATFLOAT p1_xy[2], MATFLOAT s1_xy[2],
MATFLOAT p2_xy[2], MATFLOAT p3_xy[2], MATFLOAT p_xy[2]);
/* MULTI-THREADING */
/* for multi-threading implementation the following function must be overwritten */
void gm_gen_map(struct s_gamut_map* ptr_gamut_map, int update_msk);
void gm_gen_3dlut(struct s_gamut_map* ptr_gamut_map, int num_pnts,
int bitwidth, int en_merge, unsigned short* ptr_3dlut_rgb);
/* end MULTI-THREADING */
/* global constants */
static const MATFLOAT gm_vec_org13_factor_def[GM_NUM_PRIM][2] = {
{1.3, 1.05}, /* M */
{1.3, 1.10}, /* R */
{1.3, 1.10}, /* Y */
{1.3, 1.05}, /* G */
{1.2, 1.01}, /* C */
{1.0, 1.06} /* B */
};
static const MATFLOAT gm_vec_cusp_rgb[GM_NUM_PRIM][3] = {
{1.0, 0.0, 1.0}, /* M */
{1.0, 0.0, 0.0}, /* R */
{1.0, 1.0, 0.0}, /* Y */
{0.0, 1.0, 0.0}, /* G */
{0.0, 1.0, 1.0}, /* C */
{0.0, 0.0, 1.0} /* B */
};
#ifdef __cplusplus
}
#endif

918
src/amd/gmlib/gm/mat_funcs.c Executable file
View file

@ -0,0 +1,918 @@
/*
* Copyright 2025 Advanced Micro Devices, Inc.
* SPDX-License-Identifier: MIT
*
*----------------------------------------------------------------------
* File Name : mat_funcs.c
* Purpose : Mathematical functions
* Author : Vladimir Lachine (vlachine@amd.com)
* Date : September 20, 2023
* Version : 1.2
*----------------------------------------------------------------------
*/
#ifndef GM_SIM
#pragma code_seg("PAGED3PC")
#pragma data_seg("PAGED3PD")
#pragma const_seg("PAGED3PR")
#endif
#include "mat_funcs.h"
#include <math.h>
float mat_fast_log(float x);
void mat_eval_3x3(MATFLOAT mat[3][3], MATFLOAT vec_inp[3], MATFLOAT vec_out[3])
{
int ni, nj;
mat_3x1_zero(vec_out);
for (ni = 0; ni < 3; ni++)
for (nj = 0; nj < 3; nj++)
vec_out[ni] += mat[ni][nj] * vec_inp[nj];
}
void mat_eval_3x3_off(MATFLOAT mat[3][3], MATFLOAT vec_off[3], MATFLOAT vec_inp[3], MATFLOAT vec_out[3])
{
int nc;
mat_eval_3x3(mat, vec_inp, vec_out);
for (nc = 0; nc < 3; nc++)
vec_out[nc] += vec_off[nc];
}
void mat_eval_off_3x3_off(MATFLOAT vec_off_inp[3], MATFLOAT mat[3][3],
MATFLOAT vec_off_out[3], MATFLOAT vec_inp[3], MATFLOAT vec_out[3])
{
MATFLOAT val_tmp[3];
int nc;
for (nc = 0; nc < 3; nc++)
val_tmp[nc] = vec_inp[nc] + vec_off_inp[nc];
mat_eval_3x3(mat, val_tmp, vec_out);
for (nc = 0; nc < 3; nc++)
vec_out[nc] += vec_off_out[nc];
}
void mat_mul3x3(MATFLOAT mat2[3][3], MATFLOAT mat1[3][3], MATFLOAT mat2x1[3][3])
{
int ni, nj, nk;
mat_3x3_zero(mat2x1);
for (ni = 0; ni < 3; ni++)
for (nj = 0; nj < 3; nj++)
for (nk = 0; nk < 3; nk++)
mat2x1[ni][nj] += mat2[ni][nk] * mat1[nk][nj];
}
int mat_inv3x3(MATFLOAT mat_inp[3][3], MATFLOAT mat_out[3][3])
{
/*
* Calculate the determinant of matrix A and determine if the
* the matrix is singular as limited by the MATFLOAT precision
* MATFLOATing-point data representation.
*/
MATFLOAT det = 0.0;
MATFLOAT pos = 0.0;
MATFLOAT neg = 0.0;
MATFLOAT temp;
temp = mat_inp[0][0] * mat_inp[1][1] * mat_inp[2][2];
if (temp >= 0.0)
pos += temp;
else
neg += temp;
temp = mat_inp[0][1] * mat_inp[1][2] * mat_inp[2][0];
if (temp >= 0.0)
pos += temp;
else
neg += temp;
temp = mat_inp[0][2] * mat_inp[1][0] * mat_inp[2][1];
if (temp >= 0.0)
pos += temp;
else
neg += temp;
temp = -mat_inp[0][2] * mat_inp[1][1] * mat_inp[2][0];
if (temp >= 0.0)
pos += temp;
else
neg += temp;
temp = -mat_inp[0][1] * mat_inp[1][0] * mat_inp[2][2];
if (temp >= 0.0)
pos += temp;
else
neg += temp;
temp = -mat_inp[0][0] * mat_inp[1][2] * mat_inp[2][1];
if (temp >= 0.0)
pos += temp;
else
neg += temp;
det = pos + neg;
/* Is the submatrix A singular? */
if ((det == 0.0) || (MAT_ABS(det / (pos - neg)) < PRECISION_LIMIT))
return 0; /* Matrix M has no mat_inpverse */
/* Calculate inverse(A) = adj(A) / det(A) */
mat_out[0][0] = (mat_inp[1][1] * mat_inp[2][2] - mat_inp[1][2] * mat_inp[2][1]) / det;
mat_out[1][0] = -(mat_inp[1][0] * mat_inp[2][2] - mat_inp[1][2] * mat_inp[2][0]) / det;
mat_out[2][0] = (mat_inp[1][0] * mat_inp[2][1] - mat_inp[1][1] * mat_inp[2][0]) / det;
mat_out[0][1] = -(mat_inp[0][1] * mat_inp[2][2] - mat_inp[0][2] * mat_inp[2][1]) / det;
mat_out[1][1] = (mat_inp[0][0] * mat_inp[2][2] - mat_inp[0][2] * mat_inp[2][0]) / det;
mat_out[2][1] = -(mat_inp[0][0] * mat_inp[2][1] - mat_inp[0][1] * mat_inp[2][0]) / det;
mat_out[0][2] = (mat_inp[0][1] * mat_inp[1][2] - mat_inp[0][2] * mat_inp[1][1]) / det;
mat_out[1][2] = -(mat_inp[0][0] * mat_inp[1][2] - mat_inp[0][2] * mat_inp[1][0]) / det;
mat_out[2][2] = (mat_inp[0][0] * mat_inp[1][1] - mat_inp[0][1] * mat_inp[1][0]) / det;
return 1;
}
void mat_3x1_zero(MATFLOAT vec_out[3])
{
int nc;
for (nc = 0; nc < 3; nc++)
vec_out[nc] = 0.0;
}
void mat_3x3_zero(MATFLOAT mat_out[3][3])
{
int ni, nj;
for (ni = 0; ni < 3; ni++)
for (nj = 0; nj < 3; nj++)
mat_out[ni][nj] = 0.0;
}
void mat_3x3_unity(MATFLOAT mat_out[3][3])
{
int ni, nj;
for (ni = 0; ni < 3; ni++)
for (nj = 0; nj < 3; nj++)
mat_out[ni][nj] = (ni == nj) ? 1.0f : 0.0f;
}
void mat_copy3x3(MATFLOAT mat_inp[3][3], MATFLOAT mat_out[3][3])
{
int ni, nj;
for (ni = 0; ni < 3; ni++)
for (nj = 0; nj < 3; nj++)
mat_out[ni][nj] = mat_inp[ni][nj];
}
int mat_round(MATFLOAT val)
{
int sign = MAT_ZSGN(val);
int val_out = (int)(MAT_ABS(val) + 0.5);
return sign * val_out;
}
MATFLOAT mat_int2flt(int val, int val_max)
{
return (MATFLOAT)val / (MATFLOAT)val_max;
}
int mat_flt2int(MATFLOAT val_inp, int val_max)
{
MATFLOAT val_tmp = val_inp * (MATFLOAT)val_max;
int val_out = mat_round(val_tmp);
return MAT_CLAMP(val_out, 0, val_max);
}
void mat_gen_mat_off(MATFLOAT mat_inp[3][3], MATFLOAT vec_off_inp[3],
MATFLOAT vec_off_out[3], MATFLOAT mat_res[3][3], MATFLOAT vec_off_res[3])
{
int nc;
/* construct transform. The 'inoff' is merged into output offset. */
if (vec_off_out)
for (nc = 0; nc < 3; nc++)
vec_off_res[nc] = vec_off_out[nc];
else
mat_3x1_zero(vec_off_res);
if (mat_inp)
mat_copy3x3(mat_inp, mat_res);
else
mat_3x3_unity(mat_res);
if (vec_off_inp)
for (nc = 0; nc < 3; nc++)
vec_off_res[nc] -= (mat_res[nc][0] * vec_off_inp[0] + mat_res[nc][1] *
vec_off_inp[1] + mat_res[nc][2] * vec_off_inp[2]);
}
void mat_scl_off(MATFLOAT vec_off_inp[3], MATFLOAT vec_off_out[3], int bitwidth)
{ /* output may be the same as input */
int nc;
for (nc = 0; nc < 3; nc++)
vec_off_out[nc] = vec_off_inp[nc] * (MATFLOAT)(1 << bitwidth);
}
void mat_cvt_cs(int vec_inp[3], int vec_out[3], int bitwidth,
MATFLOAT mat[3][3], MATFLOAT vec_off[3], int is_clip)
{
int nc, ni;
for (nc = 0; nc < 3; nc++) {
MATFLOAT sum = vec_off[nc];
for (ni = 0; ni < 3; ni++)
sum += mat[nc][ni] * (MATFLOAT)vec_inp[ni];
int nValue = mat_round(sum);
if (is_clip) {
const int cnMaxValue = (1 << bitwidth) - 1;
MAT_CLAMP(nValue, 0, cnMaxValue);
}
vec_out[nc] = nValue;
}
}
MATFLOAT mat_norm_angle(MATFLOAT angle)
{
MATFLOAT pi2 = 2.0f * mat_get_pi();
MATFLOAT angle_out = angle;
if (angle_out < 0.0f)
angle_out += pi2;
else if (angle_out >= pi2)
angle_out -= pi2;
return angle_out;
}
MATFLOAT mat_clamp(MATFLOAT val_inp, MATFLOAT val_min, MATFLOAT val_max)
{
return MAT_CLAMP(val_inp, val_min, val_max);
}
int mat_is_valid(MATFLOAT val_inp, MATFLOAT val_min, MATFLOAT val_max)
{
return ((mat_is_number(val_inp) == 0) || (val_inp < val_min) || (val_inp > val_max)) ? 0 : 1;
}
int mat_is_valid_vec(MATFLOAT vec_inp[], int size, MATFLOAT val_min, MATFLOAT val_max)
{
int ni;
for (ni = 0; ni < size; ni++)
if (mat_is_valid(vec_inp[ni], val_min, val_max) == 0)
return 0;
return 1;
}
int mat_is_number(MATFLOAT val)
{ /* Check if this is not NaN */
return (val == val);
}
MATFLOAT mat_norm(MATFLOAT val_inp, MATFLOAT val_min, MATFLOAT val_rng)
{ /* map to [0.0,1.0] */
return (val_inp - val_min) / val_rng;
}
MATFLOAT mat_denorm(MATFLOAT val_inp, MATFLOAT val_min, MATFLOAT val_rng)
{ /* map from [0.0,1.0] */
return val_inp * val_rng + val_min;
}
void mat_copy(MATFLOAT vec_inp[], MATFLOAT vec_out[], int size)
{
int nc;
for (nc = 0; nc < size; nc++)
vec_out[nc] = vec_inp[nc];
}
void mat_set(MATFLOAT val_inp, MATFLOAT vec_out[], int size)
{
int nc;
for (nc = 0; nc < size; nc++)
vec_out[nc] = val_inp;
}
int mat_flt_to_index(MATFLOAT val_inp, MATFLOAT val_max, int num_pnts)
{
MATFLOAT step = val_max / (MATFLOAT)(num_pnts - 1);
return (int)(val_inp / step);
}
MATFLOAT mat_index_to_flt(int index, MATFLOAT val_max, int num_pnts)
{
MATFLOAT step = val_max / (MATFLOAT)(num_pnts - 1);
return (MATFLOAT)index * step;
}
MATFLOAT mat_flt_to_index_phase(MATFLOAT val_inp, MATFLOAT val_max, int num_pnts, int vec_ind[2])
{
MATFLOAT step = val_max / (MATFLOAT)(num_pnts - 1);
MATFLOAT tmp = val_inp / step;
vec_ind[0] = (int)tmp;
vec_ind[1] = vec_ind[0] + 1;
if (vec_ind[1] > num_pnts - 1)
vec_ind[1] = num_pnts - 1;
return tmp - (MATFLOAT)vec_ind[0];
}
MATFLOAT mat_vec_to_index_phase(MATFLOAT val_inp, MATFLOAT vec_val[], int num_pnts, int vec_ind[2])
{
int ind0, ind1;
/* calculate indexes */
for (ind0 = num_pnts - 1; ind0 >= 0; ind0--) {
if (val_inp >= vec_val[ind0])
break;
}
ind1 = MAT_MIN(ind0 + 1, num_pnts - 1);
vec_ind[0] = ind0;
vec_ind[1] = ind1;
return (vec_val[ind0] == vec_val[ind1]) ? 0.0 : (val_inp - vec_val[ind0]) / (vec_val[ind1] - vec_val[ind0]);
}
int mat_int_to_index(int val_inp, int val_max, int num_indexes)
{
return val_inp * (num_indexes - 1) / val_max;
}
int mat_index_to_int(int index, int val_max, int num_indexes)
{
return index * val_max / (num_indexes - 1);
}
MATFLOAT mat_int_to_index_phase(int val_inp, int val_max, int num_indexes, int vec_val_ind[2])
{
MATFLOAT step = (MATFLOAT)val_max / (MATFLOAT)(num_indexes - 1);
vec_val_ind[0] = mat_int_to_index(val_inp, val_max, num_indexes);
vec_val_ind[1] = MAT_MIN(vec_val_ind[0] + 1, num_indexes - 1);
return (val_inp - mat_index_to_int(vec_val_ind[0], val_max, num_indexes)) / step;
}
int mat_get_hue_index_2pi(MATFLOAT vec_hue[], int num_hue_pnts)
{ /* find a point crossing 2PI */
int index_2pi;
for (index_2pi = num_hue_pnts - 1; index_2pi >= 1; index_2pi--)
if (vec_hue[index_2pi] < vec_hue[index_2pi - 1])
break;
return index_2pi;
}
MATFLOAT mat_hue_to_index_phase(MATFLOAT val_inp, int num_hue_pnts,
MATFLOAT vec_val[], MATFLOAT val_max, int index_max, int vec_ind_out[2])
{
int ind0, ind1;
MATFLOAT step, delta;
/* calculate indexes */
ind1 = index_max;
while (val_inp >= vec_val[ind1]) {
ind1 = (ind1 + 1) % num_hue_pnts;
if (ind1 == index_max)
break;
}
ind0 = (ind1 > 0) ? ind1 - 1 : num_hue_pnts - 1;
/* calculate phase */
step = vec_val[ind1] - vec_val[ind0];
if (step < 0.0)
step += val_max;
delta = val_inp - vec_val[ind0];
if (delta < 0.0)
delta += val_max;
vec_ind_out[0] = ind0;
vec_ind_out[1] = ind1;
return delta / step;
}
int mat_seg_intersection(MATFLOAT p0_xy[2], MATFLOAT p1_xy[2],
MATFLOAT p2_xy[2], MATFLOAT p3_xy[2], MATFLOAT p_xy[2])
{
MATFLOAT s1_x = p1_xy[0] - p0_xy[0];
MATFLOAT s1_y = p1_xy[1] - p0_xy[1];
MATFLOAT s2_x = p3_xy[0] - p2_xy[0];
MATFLOAT s2_y = p3_xy[1] - p2_xy[1];
MATFLOAT denom = -s2_x * s1_y + s1_x * s2_y;
MATFLOAT s0_x, s0_y, s, t;
if (denom == 0.0)
return 0; /* no collision */
s0_x = p0_xy[0] - p2_xy[0];
s0_y = p0_xy[1] - p2_xy[1];
s = (-s1_y * s0_x + s1_x * s0_y) / denom;
if ((s < 0.0) || (s > 1.0))
return 0; /* no collision */
t = (s2_x * s0_y - s2_y * s0_x) / denom;
if ((t < 0.0) || (t > 1.0))
return 0; /* no collision */
/* collision detected */
p_xy[0] = p0_xy[0] + (t * s1_x);
p_xy[1] = p0_xy[1] + (t * s1_y);
return 1;
}
MATFLOAT mat_linear(MATFLOAT vec_inp[2], MATFLOAT phs)
{
return vec_inp[0] + (vec_inp[1] - vec_inp[0]) * phs;
}
MATFLOAT mat_bilinear(MATFLOAT vec_inp[2][2], MATFLOAT vec_phs[2])
{
int ni;
MATFLOAT vec_tmp[2];
for (ni = 0; ni < 2; ni++)
vec_tmp[ni] = mat_linear(vec_inp[ni], vec_phs[0]);
return mat_linear(vec_tmp, vec_phs[1]);
}
MATFLOAT mat_trilinear(MATFLOAT vec_inp[2][2][2], MATFLOAT vec_phs[3])
{
int ni;
MATFLOAT vec_tmp[2];
for (ni = 0; ni < 2; ni++)
vec_tmp[ni] = mat_bilinear(vec_inp[ni], vec_phs);
return mat_linear(vec_tmp, vec_phs[2]);
}
MATFLOAT mat_tetra(MATFLOAT vec_inp[2][2][2], MATFLOAT vec_phs[3])
{
MATFLOAT fx = vec_phs[2];
MATFLOAT fy = vec_phs[1];
MATFLOAT fz = vec_phs[0];
MATFLOAT vec_c[3];
MATFLOAT value;
int nc;
if (fx > fy) {
if (fy > fz) { /* T0: x > y > z */
vec_c[0] = vec_inp[1][0][0] - vec_inp[0][0][0];
vec_c[1] = vec_inp[1][1][0] - vec_inp[1][0][0];
vec_c[2] = vec_inp[1][1][1] - vec_inp[1][1][0];
} else if (fx > fz) { /* T5: x > z > y */
vec_c[0] = vec_inp[1][0][0] - vec_inp[0][0][0];
vec_c[1] = vec_inp[1][1][1] - vec_inp[1][0][1];
vec_c[2] = vec_inp[1][0][1] - vec_inp[1][0][0];
} else { /* T4: z > x > y */
vec_c[0] = vec_inp[1][0][1] - vec_inp[0][0][1];
vec_c[1] = vec_inp[1][1][1] - vec_inp[1][0][1];
vec_c[2] = vec_inp[0][0][1] - vec_inp[0][0][0];
}
} else {
if (fx > fz) { /* T1: y > x > z */
vec_c[0] = vec_inp[1][1][0] - vec_inp[0][1][0];
vec_c[1] = vec_inp[0][1][0] - vec_inp[0][0][0];
vec_c[2] = vec_inp[1][1][1] - vec_inp[1][1][0];
} else if (fy > fz) { /* T2: y > z > x */
vec_c[0] = vec_inp[1][1][1] - vec_inp[0][1][1];
vec_c[1] = vec_inp[0][1][0] - vec_inp[0][0][0];
vec_c[2] = vec_inp[0][1][1] - vec_inp[0][1][0];
} else { /* T3: z > y > x */
vec_c[0] = vec_inp[1][1][1] - vec_inp[0][1][1];
vec_c[1] = vec_inp[0][1][1] - vec_inp[0][0][1];
vec_c[2] = vec_inp[0][0][1] - vec_inp[0][0][0];
}
}
value = vec_inp[0][0][0];
for (nc = 0; nc < 3; nc++)
value += vec_c[nc] * vec_phs[2 - nc];
return MAT_CLAMP(value, 0.0, 1.0);
}
MATFLOAT mat_cubic(MATFLOAT vec_inp[4], MATFLOAT phs)
{
return vec_inp[1] + 0.5 * phs * (vec_inp[2] - vec_inp[0] +
phs * (2.0 * vec_inp[0] - 5.0 * vec_inp[1] + 4.0 * vec_inp[2] - vec_inp[3] +
phs * (3.0 * (vec_inp[1] - vec_inp[2]) + vec_inp[3] - vec_inp[0])));
}
MATFLOAT mat_mse(MATFLOAT val1[], MATFLOAT val2[], int size)
{
MATFLOAT err = 0.0;
int nc;
for (nc = 0; nc < size; nc++) {
MATFLOAT err_tmp = val1[nc] - val2[nc];
err += err_tmp * err_tmp;
}
return mat_sqrt(err);
}
MATFLOAT mat_sshape(MATFLOAT val, MATFLOAT gamma)
{
MATFLOAT k = 0.5 * mat_pow(0.5, -gamma);
MATFLOAT val_out = (val <= 0.5) ? k * mat_pow(val, gamma) : 1.0 - k * mat_pow((1.0 - val), gamma);
return val_out;
}
MATFLOAT mat_radius_vec(MATFLOAT vec_val[], MATFLOAT vec_org[], int size)
{
MATFLOAT radius = 0.0;
int ni;
for (ni = 0; ni < size; ni++)
radius += (vec_val[ni] - vec_org[ni]) * (vec_val[ni] - vec_org[ni]);
return mat_sqrt(radius);
}
void mat_gain_vec(MATFLOAT vec_inp[], MATFLOAT vec_out[], MATFLOAT vec_org[], int size, MATFLOAT gain)
{
int ni;
for (ni = 0; ni < 3; ni++)
vec_out[ni] = vec_org[ni] + (vec_inp[ni] - vec_org[ni]) * gain;
}
MATFLOAT mat_get_pi(void)
{
#ifdef GM_MAT_MATH
return (MATFLOAT)acos(-1.0);
#else
return 3.14159265358979323;
#endif
}
MATFLOAT mat_angle(MATFLOAT y, MATFLOAT x)
{
return mat_norm_angle(mat_atan2(y, x));
}
MATFLOAT mat_radius(MATFLOAT y, MATFLOAT x)
{
return mat_sqrt(y * y + x * x);
}
MATFLOAT mat_pow(MATFLOAT val0, MATFLOAT val1)
{
return (MATFLOAT)pow(val0, val1);
}
MATFLOAT mat_atan2(MATFLOAT y, MATFLOAT x)
{
return (MATFLOAT)atan2(y, x);
}
MATFLOAT mat_cos(MATFLOAT val)
{
return (MATFLOAT)cos(val);
}
MATFLOAT mat_sin(MATFLOAT val)
{
return (MATFLOAT)sin(val);
}
MATFLOAT mat_log2(MATFLOAT val)
{
return (MATFLOAT)(mat_log(val) / mat_log(2.0));
}
MATFLOAT mat_log10(MATFLOAT val)
{
return (MATFLOAT)(mat_log(val) / mat_log(10.0));
}
MATFLOAT mat_frexp(MATFLOAT val, int *exponent)
{
return (MATFLOAT)frexp(val, exponent);
}
#ifndef GM_MAT_MATH
static const unsigned char root_recip_table[128] = {
0x69, 0x66, 0x63, 0x61, 0x5E, 0x5B, 0x59, 0x57, /* for x =(2.0 ... 3.99)*(4^n) */
0x54, 0x52, 0x50, 0x4D, 0x4B, 0x49, 0x47, 0x45, /* (exponent is even) */
0x43, 0x41, 0x3F, 0x3D, 0x3B, 0x39, 0x37, 0x36,
0x34, 0x32, 0x30, 0x2F, 0x2D, 0x2C, 0x2A, 0x28,
0x27, 0x25, 0x24, 0x22, 0x21, 0x1F, 0x1E, 0x1D,
0x1B, 0x1A, 0x19, 0x17, 0x16, 0x15, 0x14, 0x12,
0x11, 0x10, 0x0F, 0x0D, 0x0C, 0x0B, 0x0A, 0x09,
0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01,
0xFE, 0xFA, 0xF6, 0xF3, 0xEF, 0xEB, 0xE8, 0xE4, /* for x =(1.0 ... 1.99)*(4^n) */
0xE1, 0xDE, 0xDB, 0xD7, 0xD4, 0xD1, 0xCE, 0xCB, /* (exponent is odd) */
0xC9, 0xC6, 0xC3, 0xC0, 0xBE, 0xBB, 0xB8, 0xB6,
0xB3, 0xB1, 0xAF, 0xAC, 0xAA, 0xA8, 0xA5, 0xA3,
0xA1, 0x9F, 0x9D, 0x9B, 0x99, 0x97, 0x95, 0x93,
0x91, 0x8F, 0x8D, 0x8B, 0x89, 0x87, 0x86, 0x84,
0x82, 0x80, 0x7F, 0x7D, 0x7B, 0x7A, 0x78, 0x77,
0x75, 0x74, 0x72, 0x71, 0x6F, 0x6E, 0x6C, 0x6B
};
/*
* find a reciprocal of square-root of x, using a similar method.
* an approximation is found, using the 6 MSBs of the mantissa,
* and the LSB of the exponent.
* The exponent mapping is a bit tricker than in the RECIPS case:
* we want
* 125,126 -> 127
* 127,128 -> 126
* 129,130 -> 125
* 131,132 -> 124
*
* So, we can take original exponent, add 131, then >>1, then
* take the 1's complement.
* The result is accurate +/- 1 lsb in float precision. I'm not
* sure exactly what the full range of this is, it should
* work for any values >0, except for denormals.
*
* iterative method:
* Cavanagh, J. 1984. Digital Computer Arithmetic. McGraw-Hill. Page 278.
*/
float mat_fast_rsqrt(float val)
{
union {
float fval;
unsigned int uval;
} u;
unsigned int new_mant;
float rsqa, rprod;
u.fval = val;
u.uval &= 0x7FFFFFFF; /* can't have sign */
val = u.fval * 0.5f;
new_mant = root_recip_table[(u.uval >> 17) & 0x7F];
/*
* create modified exponent ; drop in new mantissa
*/
u.uval = (~((u.uval + 0x41800000) >> 1) & 0x7F800000) + (new_mant << 15);
rsqa = u.fval;
/*
* note: we could do
* rsqa *= 1.5f - rsqa*rsqa * x
* but there are cases where x is very small
* (zero or denormal) and rsqa*rsqa could overflow. We generate
* the wrong answer in these cases, but at least it isn't a NaN.
*/
rprod = val * rsqa;
rsqa *= 1.5f - rprod * rsqa;
rprod = val * rsqa;
rsqa *= 1.5f - rprod * rsqa;
rprod = val * rsqa;
rsqa *= 1.5f - rprod * rsqa;
return rsqa;
}
#define Declare_Special_Float(cnst) { union { unsigned int ui; float f; } u; u.ui = (cnst); return u.f; }
float FLT_INF(void);
float FLT_MINF(void);
float FLT_NAN(void);
float FLT_INF(void) Declare_Special_Float(0x7F800000);
float FLT_MINF(void) Declare_Special_Float(0xFF800000);
float FLT_NAN(void) Declare_Special_Float(0x7F800001);
/*
* table below is
* a = log(x+1), b = exp(-a);
* comment shows range of x to which each line applies.
*/
static const float log_tab[64] = {
0.000000000f, 1.000000000f, /* 0 to 0.0111657 */
0.022311565f, 0.977935498f, /* ... to 0.0340233 */
0.044580154f, 0.956398938f, /* ... to 0.0572837 */
0.066807851f, 0.935374915f, /* ... to 0.0810282 */
0.089004092f, 0.914841830f, /* ... to 0.1052765 */
0.111178130f, 0.894779348f, /* ... to 0.1300487 */
0.133338988f, 0.875168370f, /* ... to 0.1553661 */
0.155495435f, 0.855990985f, /* ... to 0.1812505 */
0.177655950f, 0.837230423f, /* ... to 0.2077248 */
0.199828684f, 0.818871027f, /* ... to 0.2348125 */
0.222021341f, 0.800898272f, /* ... to 0.2625375 */
0.244241118f, 0.783298744f, /* ... to 0.2909245 */
0.266494602f, 0.766060139f, /* ... to 0.3199984 */
0.288787603f, 0.749171310f, /* ... to 0.3497841 */
0.311125100f, 0.732622219f, /* ... to 0.3803064 */
0.333510906f, 0.716404086f, /* ... to 0.4115894 */
0.355947524f, 0.700509379f, /* ... to 0.4436560 */
0.378435910f, 0.684931867f, /* ... to 0.4765275 */
0.400975198f, 0.669666670f, /* ... to 0.5102230 */
0.423562229f, 0.654710433f, /* ... to 0.5447579 */
0.446191430f, 0.640061233f, /* ... to 0.5801435 */
0.468854219f, 0.625718795f, /* ... to 0.6163859 */
0.491538733f, 0.611684450f, /* ... to 0.6534842 */
0.514229417f, 0.597961196f, /* ... to 0.6914296 */
0.536906660f, 0.584553682f, /* ... to 0.7302038 */
0.559546530f, 0.571468149f, /* ... to 0.7697776 */
0.582120657f, 0.558712272f, /* ... to 0.8101096 */
0.604596078f, 0.546295042f, /* ... to 0.8511456 */
0.626935601f, 0.534226378f, /* ... to 0.8928175 */
0.649098098f, 0.522516823f, /* ... to 0.9350435 */
0.671039402f, 0.511176983f, /* ... to 0.9777287 */
0.693147182f, 0.500000000f, /* ....to 0.9999999 */
};
/*
* FAST LN function
*
* (1) split the number into its base-2 exponent 'e', and
* a mantissa 'xm' in range 1.0 .. 1.99999
*
* (2) using a cubic, find y0 = approx. ln(xm)
* (3) scale this, round it to a table index 0...31.
* From the table, get a log value, (which will be added to the result)
* and a scale factor.
* Multiply xm by the scale factor, result xe is very close to 1.
*
* (4) find ye = log(xe) using a taylor series around xe=1
* (5) result is is yt+ye+log(2)*exp, where yt is from the table (1st col)
* and exp is the original exponent.
* Note that multiplying the input by the second column of the the table,
* and adding the 1st column of the table to the result, has no net effect.
*/
float mat_fast_log(float x)
{
union {
float f;
unsigned int ui;
} u;
float xm1, xe, ye;
int tabind;
int ex;
u.f = x;
ex = ((u.ui >> 23) & 0x1FF) - 127;
if ((ex <= -127) || (ex >= 128)) {
if ((ex & 0xFF) == 1)
return FLT_MINF(); /* was 0.0 or -0.0 (or denormal) */
return FLT_NAN();
}
u.ui -= ex << 23;
/*
* now u.f is in range 1.0 ... 1.99999
*/
xm1 = u.f - 1.0f; /* 0. 1.0 */
/*
* The table above and the cubic below were generated together
*/
tabind = MAT_ROUND(((xm1 * 0.1328047513f - 0.4396575689f) * xm1 * xm1 + xm1) * 44.75f);
/*
* tabind is in range 0..31.
* multiply u.f by the second value in the table, subtract 1
*/
xe = u.f * log_tab[2 * tabind + 1] - 1.0f; /* result is +/- .0114 */
/*
* find the log(xe+1) using taylor series; add to (a) amount from exponent
* (b) amount from table
*/
ye = ((-0.25f * xe + 0.333333333f) * xe - 0.5f) * xe * xe;
ye += xe;
return 0.693147182f * (float)ex + log_tab[2 * tabind] + ye;
}
static const float exp_table[16] =
{
/* (1/6) * 2^(i/16.), to float precision */
0.166666672f, 0.174045637f, 0.181751296f, 0.189798102f,
0.198201180f, 0.206976309f, 0.216139928f, 0.225709260f,
0.235702261f, 0.246137694f, 0.257035136f, 0.268415064f,
0.280298799f, 0.292708695f, 0.305668026f, 0.319201082f
};
/*
* FAST_EXP does an exponential function.
* This is done using a table lookup to
* get close and a taylor series to
* get accurate.
*
* if y = exp(x) = (2^m)*(P^n)*exp(f), where P = 2^(1/16),
*
* then x = ln(2^m) + ln(P^n) + f
* = ln(P^(16*m+n)) + f
* = ln(P) * [ 16*m +n ] +f
* let k = ln(P) = ln(2)/16 = 0.043321698785
*
* so x = k*[16*m + n] + f
*
* For a given x, we find m,n,f such that:
* m is an integer
* n is in integer 0..15
* f is as close to zero as possible: +/- k/2
*
* Then we find y = (2^m)*(P^n)*exp(f)
*
* where 2^m is an exponent adjustment, P^n is a table lookup
* and exp(f) is calculated. The 4th term in the series
* for exp(f) is at most k^4/(16*24) = 9.17e-9, so we only
* need to do up to the 3rd order.
*
* One more quirk:
* exp(f) is evaluated via
* 6*exp(f) = ((f + 3)*f + 6)*f + 6
*
* To compensate, the numbers in the P^n table are really 1/6 as
* big as they should be.
*
* Example: exp(13.2)
* 13.2 * (1/k) = 304.697, round to 305 => m*16+n = 305
* f = 13.2 - k * 305 = -0.013118
* m = 19, n = 1
*
* 6*exp(f) = ((f + 3)*f + 6)*f + 6 = 5.921805
* exp_table[n] * (6*exp(f)) = .174046 * 5.921805 = 1.030664
* multiply that by 2^m (=5.24288e5) -> 5.40365e5
*
*/
float mat_fast_exp(float x)
{
int m, n;
union {
unsigned ui;
float f;
} u;
n = MAT_ROUND(x * 23.08312065f); /* 16/log(2) */
/*
* range check on n now
*/
if ((n <= -2016) || (n >= 2048)) {
if (n < 0)
return 0.0f;
else
return FLT_INF();
}
x -= (float)n * 0.043321698785f; /* log(2)/16. */
m = (n >> 4);
x = ((x + 3.0f) * x + 6.0f) * x + 6.0f;
u.f = x * exp_table[n & 15];
u.ui += (m << 23); /* exponent adjust */
return u.f;
}
#endif
MATFLOAT mat_sqrt(MATFLOAT val)
{
#ifndef GM_MAT_MATH
return 1.0 / (MATFLOAT)mat_fast_rsqrt((float)val);
#else
return (MATFLOAT)sqrt(val);
#endif
}
MATFLOAT mat_log(MATFLOAT val)
{ /* base e */
#ifdef GM_MAT_MATH
return (MATFLOAT)log(val);
#else
return (MATFLOAT)mat_fast_log((float)val);
#endif
}
MATFLOAT mat_exp(MATFLOAT val)
{
#ifdef GM_MAT_MATH
return (MATFLOAT)exp(val);
#else
return (MATFLOAT)mat_fast_exp((float)val);
#endif
}
unsigned int mat_index_3dlut(int ind_r, int ind_g, int ind_b, int num_pnts, enum mat_order_3dlut order)
{
unsigned int index;
switch (order) {
case MAT_ORDER_RGB:
index = (ind_b * num_pnts + ind_g) * num_pnts + ind_r;
break;
case MAT_ORDER_BGR:
default:
index = (ind_r * num_pnts + ind_g) * num_pnts + ind_b;
break;
}
return index;
}

143
src/amd/gmlib/gm/mat_funcs.h Executable file
View file

@ -0,0 +1,143 @@
/*
* Copyright 2025 Advanced Micro Devices, Inc.
* SPDX-License-Identifier: MIT
*
*----------------------------------------------------------------------
* File Name : mat_funcs.h
* Purpose : Mathematical functions
* Author : Vladimir Lachine (vlachine@amd.com)
* Date : September 20, 2023
* Version : 1.2
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#define MATFLOAT double
/* precision for matrix inversion */
#define PRECISION_LIMIT (1.0e-15)
/* absolute value of a */
#define MAT_ABS(a) (((a) < 0) ? -(a) : (a))
/* find minimum of a and b */
#define MAT_MIN(a, b) (((a) < (b)) ? (a) : (b))
/* find maximum of a and b */
#define MAT_MAX(a, b) (((a) > (b)) ? (a) : (b))
/* clip to range */
#define MAT_CLAMP(v, l, h) ((v) < (l) ? (l) : ((v) > (h) ? (h) : v))
/* round a to nearest int */
#define MAT_ROUND(a) (int)((a) + 0.5f)
/* take sign of a, either -1, 0, or 1 */
#define MAT_ZSGN(a) (((a) < 0) ? -1 : (a) > 0 ? 1 : 0)
/* take binary sign of a, either -1, or 1 if >= 0 */
#define MAT_SGN(a) (((a) < 0) ? -1 : 1)
/* swap a and b (see Gem by Wyvill) */
#define MAT_SWAP(a, b) { a ^ = b; b ^ = a; a ^= b; }
/* linear interpolation from l (when a=0) to h (when a=1) */
/* (equal to (a*h)+((1-a)*l) */
#define MAT_LERP(a, l, h) ((l) + (((h) - (l)) * (a)))
/* vector operations */
void mat_eval_3x3(MATFLOAT mat[3][3], MATFLOAT vec_inp[3], MATFLOAT vec_out[3]);
void mat_eval_3x3_off(MATFLOAT mat[3][3], MATFLOAT vec_off[3], MATFLOAT vec_inp[3], MATFLOAT vec_out[3]);
void mat_eval_off_3x3_off(MATFLOAT vec_off_inp[3], MATFLOAT mat[3][3],
MATFLOAT vec_off_out[3], MATFLOAT vec_inp[3], MATFLOAT vec_out[3]);
void mat_mul3x3(MATFLOAT mat2[3][3], MATFLOAT mat1[3][3], MATFLOAT mat2x1[3][3]);
int mat_inv3x3(MATFLOAT mat_inp[3][3], MATFLOAT mat_out[3][3]);
void mat_3x1_zero(MATFLOAT vec_out[3]);
void mat_3x3_zero(MATFLOAT mat_out[3][3]);
void mat_3x3_unity(MATFLOAT mat_out[3][3]);
void mat_copy3x3(MATFLOAT mat_inp[3][3], MATFLOAT mat_out[3][3]);
int mat_round(MATFLOAT val);
MATFLOAT mat_int2flt(int val, int val_max);
int mat_flt2int(MATFLOAT val, int val_max);
void mat_gen_mat_off(MATFLOAT mat_inp[3][3], MATFLOAT vec_off_inp[3],
MATFLOAT vec_off_out[3], MATFLOAT mat_res[3][3], MATFLOAT vec_off_res[3]);
void mat_scl_off(MATFLOAT vec_off_inp[3], MATFLOAT vec_off_out[3], int bitwidth);
void mat_cvt_cs(int vec_inp[3], int vec_out[3], int bitwidth, MATFLOAT mat[3][3], MATFLOAT vec_off[3], int is_clip);
MATFLOAT mat_norm_angle(MATFLOAT angle);
MATFLOAT mat_clamp(MATFLOAT val_inp, MATFLOAT val_min, MATFLOAT val_max);
int mat_is_valid(MATFLOAT val_inp, MATFLOAT val_min, MATFLOAT val_max);
int mat_is_valid_vec(MATFLOAT val_inp[], int size, MATFLOAT val_min, MATFLOAT val_max);
int mat_is_number(MATFLOAT val);
MATFLOAT mat_norm(MATFLOAT val_inp, MATFLOAT val_min, MATFLOAT val_rng);
MATFLOAT mat_denorm(MATFLOAT val_inp, MATFLOAT val_min, MATFLOAT val_rng);
void mat_copy(MATFLOAT vec_inp[], MATFLOAT vec_out[], int size);
void mat_set(MATFLOAT val_inp, MATFLOAT vec_out[], int size);
int mat_flt_to_index(MATFLOAT val_inp, MATFLOAT val_max, int num_pnts);
MATFLOAT mat_index_to_flt(int index, MATFLOAT val_max, int num_pnts);
MATFLOAT mat_flt_to_index_phase(MATFLOAT val_inp, MATFLOAT val_max, int num_pnts, int vec_ind[2]);
MATFLOAT mat_vec_to_index_phase(MATFLOAT val_inp, MATFLOAT vec_val[], int num_pnts, int vec_ind[2]);
int mat_int_to_index(int val_inp, int val_max, int num_indexes);
int mat_index_to_int(int index, int val_max, int num_indexes);
MATFLOAT mat_int_to_index_phase(int val_inp, int val_max, int num_indexes, int vec_val_ind[2]);
int mat_get_hue_index_2pi(MATFLOAT vec_hue[], int num_hue_pnts);
MATFLOAT mat_hue_to_index_phase(MATFLOAT val_inp, int num_hue_pnts,
MATFLOAT vec_val[], MATFLOAT val_max, int index_max, int vec_ind_out[2]);
int mat_seg_intersection(MATFLOAT p0_xy[2], MATFLOAT p1_xy[2],
MATFLOAT p2_xy[2], MATFLOAT p3_xy[2], MATFLOAT p_xy[2]);
MATFLOAT mat_linear(MATFLOAT vec_inp[2], MATFLOAT phs);
MATFLOAT mat_bilinear(MATFLOAT vec_inp[2][2], MATFLOAT vec_phs[2]);
MATFLOAT mat_trilinear(MATFLOAT vec_inp[2][2][2], MATFLOAT vec_phs[3]);
MATFLOAT mat_tetra(MATFLOAT vec_inp[2][2][2], MATFLOAT vec_phs[3]);
MATFLOAT mat_cubic(MATFLOAT vec_inp[4], MATFLOAT phs);
MATFLOAT mat_mse(MATFLOAT val1[], MATFLOAT val2[], int size);
MATFLOAT mat_sshape(MATFLOAT val, MATFLOAT gamma);
MATFLOAT mat_get_pi(void);
MATFLOAT mat_angle(MATFLOAT y, MATFLOAT x);
MATFLOAT mat_radius(MATFLOAT y, MATFLOAT x);
MATFLOAT mat_radius_vec(MATFLOAT val[], MATFLOAT org[], int size);
void mat_gain_vec(MATFLOAT vec_inp[], MATFLOAT vec_out[], MATFLOAT vec_org[], int size, MATFLOAT gain);
MATFLOAT mat_pow(MATFLOAT val0, MATFLOAT val1);
MATFLOAT mat_atan2(MATFLOAT y, MATFLOAT x);
MATFLOAT mat_cos(MATFLOAT val);
MATFLOAT mat_sin(MATFLOAT val);
MATFLOAT mat_sqrt(MATFLOAT val);
MATFLOAT mat_log(MATFLOAT val);
MATFLOAT mat_log2(MATFLOAT val);
MATFLOAT mat_log10(MATFLOAT val);
MATFLOAT mat_frexp(MATFLOAT val, int *exponent);
#ifndef GM_MAT_MATH
float mat_fast_rsqrt(float val);
float mat_fast_exp(float x);
#endif
MATFLOAT mat_exp(MATFLOAT val);
enum mat_order_3dlut {
MAT_ORDER_RGB = 0,
MAT_ORDER_BGR = 1
};
unsigned int mat_index_3dlut(int ind_r, int ind_g, int ind_b, int num_pnts, enum mat_order_3dlut order);
#ifdef __cplusplus
}
#endif

65
src/amd/gmlib/meson.build Executable file
View file

@ -0,0 +1,65 @@
# Copyright 2022 Advanced Micro Devices, Inc.
# SPDX-License-Identifier: MIT
c_args_gm = cc.get_supported_arguments([
'-Wall',
'-Wextra',
'-Wno-unused',
'-Wno-unused-parameter',
'-Wno-unused-command-line-argument',
'-Wno-ignored-qualifiers',
'-Wno-missing-field-initializers',
'-Wno-self-assign',
'-Wno-implicit-fallthrough',
'-Werror=comment',
'-Werror=missing-braces',
'-Werror=override-init',
'-Werror=enum-conversion',
'-Werror=enum-compare',
'-Werror=maybe-uninitialized',
])
c_args_gm += [
'-DGM_SIM',
]
gm_files = files(
'tonemap_adaptor.h',
'tonemap_adaptor.c',
'gm/csc_api_funcs.c',
'gm/csc_api_funcs.h',
'gm/csc_funcs.c',
'gm/csc_funcs.h',
'gm/cs_funcs.c',
'gm/cs_funcs.h',
'gm/cvd_api_funcs.c',
'gm/cvd_api_funcs.h',
'gm/cvd_funcs.c',
'gm/cvd_funcs.h',
'gm/gm_api_funcs.c',
'gm/gm_api_funcs.h',
'gm/gm_funcs.c',
'gm/gm_funcs.h',
'gm/mat_funcs.c',
'gm/mat_funcs.h',
'ToneMapGenerator/inc/ToneMapGenerator.h',
'ToneMapGenerator/inc/ToneMapTypes.h',
'ToneMapGenerator/src/inc/AGMGenerator.h',
'ToneMapGenerator/src/inc/CSCGenerator.h',
'ToneMapGenerator/src/src/AGMGenerator.c',
'ToneMapGenerator/src/src/ToneMapGenerator.c',
)
inc_amd_gm = include_directories(
'gm',
'ToneMapGenerator/inc',
'ToneMapGenerator/src/inc',
)
libgm = static_library(
'libgm.a',
gm_files,
install : false,
c_args : c_args_gm,
include_directories : inc_amd_gm
)

78
src/amd/gmlib/tonemap_adaptor.c Executable file
View file

@ -0,0 +1,78 @@
/* Copyright 2025 Advanced Micro Devices, Inc.
* SPDX-License-Identifier: MIT
*
* Authors: AMD
*
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include "ToneMapGenerator.h"
#include "AGMGenerator.h"
#include "tonemap_adaptor.h"
static void VPEFree3DLut(void* memToFree, void* pDevice)
{
free(memToFree);
}
static void* VPEAlloc3DLut(unsigned int allocSize, void* pDevice)
{
return calloc(1, allocSize);
}
void* tm_create(void)
{
struct ToneMapGenerator* p_tmGenerator = (struct ToneMapGenerator*)calloc(1, sizeof(struct ToneMapGenerator));
if (!p_tmGenerator)
return NULL;
p_tmGenerator->tmAlgo = TMG_A_AGM;
p_tmGenerator->memAllocSet = false;
p_tmGenerator->agmGenerator.initalized = false;
return (void*)p_tmGenerator;
}
void tm_destroy(void** pp_tmGenerator)
{
struct ToneMapGenerator* p_tmGenerator;
if (!pp_tmGenerator || ((*pp_tmGenerator) == NULL))
return;
p_tmGenerator = *pp_tmGenerator;
AGMGenerator_Exit(&p_tmGenerator->agmGenerator);
free(p_tmGenerator);
*pp_tmGenerator = NULL;
}
int tm_generate3DLut(struct tonemap_param* pInparam, void* pformattedLutData)
{
enum TMGReturnCode result;
struct ToneMappingParameters tmParams;
tmParams.lutData = (uint16_t *)pformattedLutData;
ToneMapGenerator_SetInternalAllocators(
(struct ToneMapGenerator*)pInparam->tm_handle,
(TMGAlloc)(VPEAlloc3DLut),
(TMGFree)(VPEFree3DLut),
(void*)(NULL));
result = ToneMapGenerator_GenerateToneMappingParameters(
(struct ToneMapGenerator*)pInparam->tm_handle,
&pInparam->streamMetaData,
&pInparam->dstMetaData,
pInparam->inputContainerGamma,
pInparam->outputContainerGamma,
pInparam->outputContainerPrimaries,
pInparam->lutDim,
&tmParams
);
return (int)result;
}

33
src/amd/gmlib/tonemap_adaptor.h Executable file
View file

@ -0,0 +1,33 @@
/* Copyright 2025 Advanced Micro Devices, Inc.
* SPDX-License-Identifier: MIT
*
* Authors: AMD
*
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include "ToneMapGenerator/inc/ToneMapTypes.h"
struct tonemap_param
{
void* tm_handle;
struct ToneMapHdrMetaData streamMetaData;
struct ToneMapHdrMetaData dstMetaData;
enum ToneMapTransferFunction inputContainerGamma;
enum ToneMapTransferFunction outputContainerGamma;
enum ToneMapColorPrimaries outputContainerPrimaries;
unsigned short lutDim;
};
void* tm_create(void);
void tm_destroy(void** pp_tmGenerator);
int tm_generate3DLut(struct tonemap_param* pInparam, void* pformattedLutData);
#ifdef __cplusplus
}
#endif

View file

@ -27,4 +27,5 @@ endif
if with_gallium_radeonsi
subdir('vpelib')
subdir('gmlib')
endif