Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
@@ -0,0 +1,33 @@
#
# Copyright 2017 Advanced Micro Devices, Inc.
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
# OTHER DEALINGS IN THE SOFTWARE.
#
#
# Makefile for the 'spl' sub-component of DAL.
# It provides the scaling library interface.
SPL = dc_spl.o dc_spl_scl_filters.o dc_spl_scl_easf_filters.o dc_spl_isharp_filters.o dc_spl_filters.o spl_fixpt31_32.o spl_custom_float.o
AMD_DAL_SPL = $(addprefix $(AMDDALPATH)/dc/sspl/,$(SPL))
AMD_DISPLAY_FILES += $(AMD_DAL_SPL)
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,19 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2024 Advanced Micro Devices, Inc.
#ifndef __DC_SPL_H__
#define __DC_SPL_H__
#include "dc_spl_types.h"
#define BLACK_OFFSET_RGB_Y 0x0
#define BLACK_OFFSET_CBCR 0x8000
/* SPL interfaces */
bool SPL_NAMESPACE(spl_calculate_scaler_params(struct spl_in *spl_in, struct spl_out *spl_out));
bool SPL_NAMESPACE(spl_get_number_of_taps(struct spl_in *spl_in, struct spl_out *spl_out));
#endif /* __DC_SPL_H__ */
@@ -0,0 +1,15 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2024 Advanced Micro Devices, Inc.
#include "dc_spl_filters.h"
void SPL_NAMESPACE(convert_filter_s1_10_to_s1_12(const uint16_t *s1_10_filter,
uint16_t *s1_12_filter, int num_taps))
{
int num_entries = NUM_PHASES_COEFF * num_taps;
int i;
for (i = 0; i < num_entries; i++)
*(s1_12_filter + i) = *(s1_10_filter + i) * 4;
}
@@ -0,0 +1,15 @@
/* SPDX-License-Identifier: MIT */
/* Copyright 2024 Advanced Micro Devices, Inc. */
#ifndef __DC_SPL_FILTERS_H__
#define __DC_SPL_FILTERS_H__
#include "dc_spl_types.h"
#define NUM_PHASES_COEFF 33
void SPL_NAMESPACE(convert_filter_s1_10_to_s1_12(const uint16_t *s1_10_filter,
uint16_t *s1_12_filter, int num_taps));
#endif /* __DC_SPL_FILTERS_H__ */
@@ -0,0 +1,554 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2024 Advanced Micro Devices, Inc.
#include "spl_debug.h"
#include "dc_spl_filters.h"
#include "dc_spl_isharp_filters.h"
//========================================
// Delta Gain 1DLUT
// LUT content is packed as 4-bytes into one DWORD/entry
// A_start = 0.000000
// A_end = 10.000000
// A_gain = 3.000000
// B_start = 11.000000
// B_end = 127.000000
// C_start = 40.000000
// C_end = 127.000000
//========================================
static const uint32_t filter_isharp_1D_lut_3p0x[ISHARP_LUT_TABLE_SIZE] = {
0x03010000,
0x0F0B0805,
0x211E1813,
0x2B292624,
0x3533302E,
0x3E3C3A37,
0x46444240,
0x4D4B4A48,
0x5352504F,
0x59575655,
0x5D5C5B5A,
0x61605F5E,
0x64646362,
0x66666565,
0x68686767,
0x68686868,
0x68686868,
0x67676868,
0x65656666,
0x62636464,
0x5E5F6061,
0x5A5B5C5D,
0x55565759,
0x4F505253,
0x484A4B4D,
0x40424446,
0x373A3C3E,
0x2E303335,
0x2426292B,
0x191B1E21,
0x0D101316,
0x0003060A,
};
// Blur and scale coefficients
//========================================================
// <using> gen_BlurScale_coeffs.m
// <date> 25-Apr-2022
// <num_taps> 4
// <num_phases> 64
// <CoefType> Blur & Scale LPF
// <CoefQuant> S1.10
//========================================================
static const uint16_t filter_isharp_bs_4tap_in_6_64p[198] = {
0x0000, 0x00E5, 0x0237, 0x00E4, 0x0000, 0x0000,
0x0000, 0x00DE, 0x0237, 0x00EB, 0x0000, 0x0000,
0x0000, 0x00D7, 0x0236, 0x00F2, 0x0001, 0x0000,
0x0000, 0x00D0, 0x0235, 0x00FA, 0x0001, 0x0000,
0x0000, 0x00C9, 0x0234, 0x0101, 0x0002, 0x0000,
0x0000, 0x00C2, 0x0233, 0x0108, 0x0003, 0x0000,
0x0000, 0x00BB, 0x0232, 0x0110, 0x0003, 0x0000,
0x0000, 0x00B5, 0x0230, 0x0117, 0x0004, 0x0000,
0x0000, 0x00AE, 0x022E, 0x011F, 0x0005, 0x0000,
0x0000, 0x00A8, 0x022C, 0x0126, 0x0006, 0x0000,
0x0000, 0x00A2, 0x022A, 0x012D, 0x0007, 0x0000,
0x0000, 0x009C, 0x0228, 0x0134, 0x0008, 0x0000,
0x0000, 0x0096, 0x0225, 0x013C, 0x0009, 0x0000,
0x0000, 0x0090, 0x0222, 0x0143, 0x000B, 0x0000,
0x0000, 0x008A, 0x021F, 0x014B, 0x000C, 0x0000,
0x0000, 0x0085, 0x021C, 0x0151, 0x000E, 0x0000,
0x0000, 0x007F, 0x0218, 0x015A, 0x000F, 0x0000,
0x0000, 0x007A, 0x0215, 0x0160, 0x0011, 0x0000,
0x0000, 0x0074, 0x0211, 0x0168, 0x0013, 0x0000,
0x0000, 0x006F, 0x020D, 0x016F, 0x0015, 0x0000,
0x0000, 0x006A, 0x0209, 0x0176, 0x0017, 0x0000,
0x0000, 0x0065, 0x0204, 0x017E, 0x0019, 0x0000,
0x0000, 0x0060, 0x0200, 0x0185, 0x001B, 0x0000,
0x0000, 0x005C, 0x01FB, 0x018C, 0x001D, 0x0000,
0x0000, 0x0057, 0x01F6, 0x0193, 0x0020, 0x0000,
0x0000, 0x0053, 0x01F1, 0x019A, 0x0022, 0x0000,
0x0000, 0x004E, 0x01EC, 0x01A1, 0x0025, 0x0000,
0x0000, 0x004A, 0x01E6, 0x01A8, 0x0028, 0x0000,
0x0000, 0x0046, 0x01E1, 0x01AF, 0x002A, 0x0000,
0x0000, 0x0042, 0x01DB, 0x01B6, 0x002D, 0x0000,
0x0000, 0x003F, 0x01D5, 0x01BB, 0x0031, 0x0000,
0x0000, 0x003B, 0x01CF, 0x01C2, 0x0034, 0x0000,
0x0000, 0x0037, 0x01C9, 0x01C9, 0x0037, 0x0000
};
//========================================================
// <using> gen_BlurScale_coeffs.m
// <date> 25-Apr-2022
// <num_taps> 4
// <num_phases> 64
// <CoefType> Blur & Scale LPF
// <CoefQuant> S1.10
//========================================================
static const uint16_t filter_isharp_bs_4tap_64p[132] = {
0x00E5, 0x0237, 0x00E4, 0x0000,
0x00DE, 0x0237, 0x00EB, 0x0000,
0x00D7, 0x0236, 0x00F2, 0x0001,
0x00D0, 0x0235, 0x00FA, 0x0001,
0x00C9, 0x0234, 0x0101, 0x0002,
0x00C2, 0x0233, 0x0108, 0x0003,
0x00BB, 0x0232, 0x0110, 0x0003,
0x00B5, 0x0230, 0x0117, 0x0004,
0x00AE, 0x022E, 0x011F, 0x0005,
0x00A8, 0x022C, 0x0126, 0x0006,
0x00A2, 0x022A, 0x012D, 0x0007,
0x009C, 0x0228, 0x0134, 0x0008,
0x0096, 0x0225, 0x013C, 0x0009,
0x0090, 0x0222, 0x0143, 0x000B,
0x008A, 0x021F, 0x014B, 0x000C,
0x0085, 0x021C, 0x0151, 0x000E,
0x007F, 0x0218, 0x015A, 0x000F,
0x007A, 0x0215, 0x0160, 0x0011,
0x0074, 0x0211, 0x0168, 0x0013,
0x006F, 0x020D, 0x016F, 0x0015,
0x006A, 0x0209, 0x0176, 0x0017,
0x0065, 0x0204, 0x017E, 0x0019,
0x0060, 0x0200, 0x0185, 0x001B,
0x005C, 0x01FB, 0x018C, 0x001D,
0x0057, 0x01F6, 0x0193, 0x0020,
0x0053, 0x01F1, 0x019A, 0x0022,
0x004E, 0x01EC, 0x01A1, 0x0025,
0x004A, 0x01E6, 0x01A8, 0x0028,
0x0046, 0x01E1, 0x01AF, 0x002A,
0x0042, 0x01DB, 0x01B6, 0x002D,
0x003F, 0x01D5, 0x01BB, 0x0031,
0x003B, 0x01CF, 0x01C2, 0x0034,
0x0037, 0x01C9, 0x01C9, 0x0037,
};
//========================================================
// <using> gen_BlurScale_coeffs.m
// <date> 09-Jun-2022
// <num_taps> 3
// <num_phases> 64
// <CoefType> Blur & Scale LPF
// <CoefQuant> S1.10
//========================================================
static const uint16_t filter_isharp_bs_3tap_64p[99] = {
0x0200, 0x0200, 0x0000,
0x01F6, 0x0206, 0x0004,
0x01EC, 0x020B, 0x0009,
0x01E2, 0x0211, 0x000D,
0x01D8, 0x0216, 0x0012,
0x01CE, 0x021C, 0x0016,
0x01C4, 0x0221, 0x001B,
0x01BA, 0x0226, 0x0020,
0x01B0, 0x022A, 0x0026,
0x01A6, 0x022F, 0x002B,
0x019C, 0x0233, 0x0031,
0x0192, 0x0238, 0x0036,
0x0188, 0x023C, 0x003C,
0x017E, 0x0240, 0x0042,
0x0174, 0x0244, 0x0048,
0x016A, 0x0248, 0x004E,
0x0161, 0x024A, 0x0055,
0x0157, 0x024E, 0x005B,
0x014D, 0x0251, 0x0062,
0x0144, 0x0253, 0x0069,
0x013A, 0x0256, 0x0070,
0x0131, 0x0258, 0x0077,
0x0127, 0x025B, 0x007E,
0x011E, 0x025C, 0x0086,
0x0115, 0x025E, 0x008D,
0x010B, 0x0260, 0x0095,
0x0102, 0x0262, 0x009C,
0x00F9, 0x0263, 0x00A4,
0x00F0, 0x0264, 0x00AC,
0x00E7, 0x0265, 0x00B4,
0x00DF, 0x0264, 0x00BD,
0x00D6, 0x0265, 0x00C5,
0x00CD, 0x0266, 0x00CD,
};
/* Converted Blur & Scale coeff tables from S1.10 to S1.12 */
static const uint16_t filter_isharp_bs_4tap_in_6_64p_s1_12[198] = {
0x0000, 0x0394, 0x08dc, 0x0390, 0x0000, 0x0000,
0x0000, 0x0378, 0x08dc, 0x03ac, 0x0000, 0x0000,
0x0000, 0x035c, 0x08d8, 0x03c8, 0x0004, 0x0000,
0x0000, 0x0340, 0x08d4, 0x03e8, 0x0004, 0x0000,
0x0000, 0x0324, 0x08d0, 0x0404, 0x0008, 0x0000,
0x0000, 0x0308, 0x08cc, 0x0420, 0x000c, 0x0000,
0x0000, 0x02ec, 0x08c8, 0x0440, 0x000c, 0x0000,
0x0000, 0x02d4, 0x08c0, 0x045c, 0x0010, 0x0000,
0x0000, 0x02b8, 0x08b8, 0x047c, 0x0014, 0x0000,
0x0000, 0x02a0, 0x08b0, 0x0498, 0x0018, 0x0000,
0x0000, 0x0288, 0x08a8, 0x04b4, 0x001c, 0x0000,
0x0000, 0x0270, 0x08a0, 0x04d0, 0x0020, 0x0000,
0x0000, 0x0258, 0x0894, 0x04f0, 0x0024, 0x0000,
0x0000, 0x0240, 0x0888, 0x050c, 0x002c, 0x0000,
0x0000, 0x0228, 0x087c, 0x052c, 0x0030, 0x0000,
0x0000, 0x0214, 0x0870, 0x0544, 0x0038, 0x0000,
0x0000, 0x01fc, 0x0860, 0x0568, 0x003c, 0x0000,
0x0000, 0x01e8, 0x0854, 0x0580, 0x0044, 0x0000,
0x0000, 0x01d0, 0x0844, 0x05a0, 0x004c, 0x0000,
0x0000, 0x01bc, 0x0834, 0x05bc, 0x0054, 0x0000,
0x0000, 0x01a8, 0x0824, 0x05d8, 0x005c, 0x0000,
0x0000, 0x0194, 0x0810, 0x05f8, 0x0064, 0x0000,
0x0000, 0x0180, 0x0800, 0x0614, 0x006c, 0x0000,
0x0000, 0x0170, 0x07ec, 0x0630, 0x0074, 0x0000,
0x0000, 0x015c, 0x07d8, 0x064c, 0x0080, 0x0000,
0x0000, 0x014c, 0x07c4, 0x0668, 0x0088, 0x0000,
0x0000, 0x0138, 0x07b0, 0x0684, 0x0094, 0x0000,
0x0000, 0x0128, 0x0798, 0x06a0, 0x00a0, 0x0000,
0x0000, 0x0118, 0x0784, 0x06bc, 0x00a8, 0x0000,
0x0000, 0x0108, 0x076c, 0x06d8, 0x00b4, 0x0000,
0x0000, 0x00fc, 0x0754, 0x06ec, 0x00c4, 0x0000,
0x0000, 0x00ec, 0x073c, 0x0708, 0x00d0, 0x0000,
0x0000, 0x00dc, 0x0724, 0x0724, 0x00dc, 0x0000,
};
static const uint16_t filter_isharp_bs_4tap_64p_s1_12[132] = {
0x0394, 0x08dc, 0x0390, 0x0000,
0x0378, 0x08dc, 0x03ac, 0x0000,
0x035c, 0x08d8, 0x03c8, 0x0004,
0x0340, 0x08d4, 0x03e8, 0x0004,
0x0324, 0x08d0, 0x0404, 0x0008,
0x0308, 0x08cc, 0x0420, 0x000c,
0x02ec, 0x08c8, 0x0440, 0x000c,
0x02d4, 0x08c0, 0x045c, 0x0010,
0x02b8, 0x08b8, 0x047c, 0x0014,
0x02a0, 0x08b0, 0x0498, 0x0018,
0x0288, 0x08a8, 0x04b4, 0x001c,
0x0270, 0x08a0, 0x04d0, 0x0020,
0x0258, 0x0894, 0x04f0, 0x0024,
0x0240, 0x0888, 0x050c, 0x002c,
0x0228, 0x087c, 0x052c, 0x0030,
0x0214, 0x0870, 0x0544, 0x0038,
0x01fc, 0x0860, 0x0568, 0x003c,
0x01e8, 0x0854, 0x0580, 0x0044,
0x01d0, 0x0844, 0x05a0, 0x004c,
0x01bc, 0x0834, 0x05bc, 0x0054,
0x01a8, 0x0824, 0x05d8, 0x005c,
0x0194, 0x0810, 0x05f8, 0x0064,
0x0180, 0x0800, 0x0614, 0x006c,
0x0170, 0x07ec, 0x0630, 0x0074,
0x015c, 0x07d8, 0x064c, 0x0080,
0x014c, 0x07c4, 0x0668, 0x0088,
0x0138, 0x07b0, 0x0684, 0x0094,
0x0128, 0x0798, 0x06a0, 0x00a0,
0x0118, 0x0784, 0x06bc, 0x00a8,
0x0108, 0x076c, 0x06d8, 0x00b4,
0x00fc, 0x0754, 0x06ec, 0x00c4,
0x00ec, 0x073c, 0x0708, 0x00d0,
0x00dc, 0x0724, 0x0724, 0x00dc,
};
static const uint16_t filter_isharp_bs_3tap_64p_s1_12[99] = {
0x0800, 0x0800, 0x0000,
0x07d8, 0x0818, 0x0010,
0x07b0, 0x082c, 0x0024,
0x0788, 0x0844, 0x0034,
0x0760, 0x0858, 0x0048,
0x0738, 0x0870, 0x0058,
0x0710, 0x0884, 0x006c,
0x06e8, 0x0898, 0x0080,
0x06c0, 0x08a8, 0x0098,
0x0698, 0x08bc, 0x00ac,
0x0670, 0x08cc, 0x00c4,
0x0648, 0x08e0, 0x00d8,
0x0620, 0x08f0, 0x00f0,
0x05f8, 0x0900, 0x0108,
0x05d0, 0x0910, 0x0120,
0x05a8, 0x0920, 0x0138,
0x0584, 0x0928, 0x0154,
0x055c, 0x0938, 0x016c,
0x0534, 0x0944, 0x0188,
0x0510, 0x094c, 0x01a4,
0x04e8, 0x0958, 0x01c0,
0x04c4, 0x0960, 0x01dc,
0x049c, 0x096c, 0x01f8,
0x0478, 0x0970, 0x0218,
0x0454, 0x0978, 0x0234,
0x042c, 0x0980, 0x0254,
0x0408, 0x0988, 0x0270,
0x03e4, 0x098c, 0x0290,
0x03c0, 0x0990, 0x02b0,
0x039c, 0x0994, 0x02d0,
0x037c, 0x0990, 0x02f4,
0x0358, 0x0994, 0x0314,
0x0334, 0x0998, 0x0334,
};
/* Pre-generated 1DLUT for given setup and sharpness level */
static struct isharp_1D_lut_pregen filter_isharp_1D_lut_pregen[NUM_SHARPNESS_SETUPS] = {
{
0, 0,
{
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
}
},
{
0, 0,
{
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
}
},
{
0, 0,
{
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
}
},
{
0, 0,
{
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
}
},
};
static struct scale_ratio_to_sharpness_level_adj sharpness_level_adj[NUM_SHARPNESS_ADJ_LEVELS] = {
{1125, 1000, 0},
{11, 10, 1},
{1075, 1000, 2},
{105, 100, 3},
{1025, 1000, 4},
{1, 1, 5},
};
static unsigned int spl_calculate_sharpness_level_adj(struct spl_fixed31_32 ratio)
{
int j;
struct spl_fixed31_32 ratio_level;
struct scale_ratio_to_sharpness_level_adj *lookup_ptr;
unsigned int sharpness_level_down_adj;
/*
* Adjust sharpness level based on current scaling ratio
*
* We have 5 discrete scaling ratios which we will use to adjust the
* sharpness level down by 1 as we pass each ratio. The ratios
* are
*
* 1.125 upscale and higher - no adj
* 1.100 - under 1.125 - adj level down 1
* 1.075 - under 1.100 - adj level down 2
* 1.050 - under 1.075 - adj level down 3
* 1.025 - under 1.050 - adj level down 4
* 1.000 - under 1.025 - adj level down 5
*
*/
j = 0;
sharpness_level_down_adj = 0;
lookup_ptr = sharpness_level_adj;
while (j < NUM_SHARPNESS_ADJ_LEVELS) {
ratio_level = SPL_NAMESPACE(spl_fixpt_from_fraction(lookup_ptr->ratio_numer,
lookup_ptr->ratio_denom));
if (ratio.value >= ratio_level.value) {
sharpness_level_down_adj = lookup_ptr->level_down_adj;
break;
}
lookup_ptr++;
j++;
}
return sharpness_level_down_adj;
}
static unsigned int spl_calculate_sharpness_level(struct spl_fixed31_32 ratio,
unsigned int discrete_sharpness_level, enum system_setup setup,
struct spl_sharpness_range sharpness_range,
enum scale_to_sharpness_policy scale_to_sharpness_policy)
{
unsigned int sharpness_level = 0;
unsigned int sharpness_level_down_adj = 0;
int min_sharpness, max_sharpness, mid_sharpness;
/*
* Adjust sharpness level if policy requires we adjust it based on
* scale ratio. Based on scale ratio, we may adjust the sharpness
* level down by a certain number of steps. We will not select
* a sharpness value of 0 so the lowest sharpness level will be
* 0 or 1 depending on what the min_sharpness is
*
* If the policy is no required, this code maybe removed at a later
* date
*/
switch (setup) {
case HDR_L:
min_sharpness = sharpness_range.hdr_rgb_min;
max_sharpness = sharpness_range.hdr_rgb_max;
mid_sharpness = sharpness_range.hdr_rgb_mid;
if (scale_to_sharpness_policy == SCALE_TO_SHARPNESS_ADJ_ALL)
sharpness_level_down_adj = spl_calculate_sharpness_level_adj(ratio);
break;
case HDR_NL:
/* currently no use case, use Non-linear SDR values for now */
case SDR_NL:
min_sharpness = sharpness_range.sdr_yuv_min;
max_sharpness = sharpness_range.sdr_yuv_max;
mid_sharpness = sharpness_range.sdr_yuv_mid;
if (scale_to_sharpness_policy >= SCALE_TO_SHARPNESS_ADJ_YUV)
sharpness_level_down_adj = spl_calculate_sharpness_level_adj(ratio);
break;
case SDR_L:
default:
min_sharpness = sharpness_range.sdr_rgb_min;
max_sharpness = sharpness_range.sdr_rgb_max;
mid_sharpness = sharpness_range.sdr_rgb_mid;
if (scale_to_sharpness_policy == SCALE_TO_SHARPNESS_ADJ_ALL)
sharpness_level_down_adj = spl_calculate_sharpness_level_adj(ratio);
break;
}
if ((min_sharpness == 0) && (sharpness_level_down_adj >= discrete_sharpness_level))
discrete_sharpness_level = 1;
else if (sharpness_level_down_adj >= discrete_sharpness_level)
discrete_sharpness_level = 0;
else
discrete_sharpness_level -= sharpness_level_down_adj;
int lower_half_step_size = (mid_sharpness - min_sharpness) / 5;
int upper_half_step_size = (max_sharpness - mid_sharpness) / 5;
// lower half linear approximation
if (discrete_sharpness_level < 5)
sharpness_level = min_sharpness + (lower_half_step_size * discrete_sharpness_level);
// upper half linear approximation
else
sharpness_level = mid_sharpness + (upper_half_step_size * (discrete_sharpness_level - 5));
return sharpness_level;
}
void SPL_NAMESPACE(spl_build_isharp_1dlut_from_reference_curve(
struct spl_fixed31_32 ratio, enum system_setup setup,
struct adaptive_sharpness sharpness, enum scale_to_sharpness_policy scale_to_sharpness_policy))
{
uint8_t *byte_ptr_1dlut_src, *byte_ptr_1dlut_dst;
struct spl_fixed31_32 sharp_base, sharp_calc, sharp_level;
int j;
int size_1dlut;
int sharp_calc_int;
uint32_t filter_pregen_store[ISHARP_LUT_TABLE_SIZE];
/* Custom sharpnessX1000 value */
unsigned int sharpnessX1000 = spl_calculate_sharpness_level(ratio,
sharpness.sharpness_level, setup,
sharpness.sharpness_range, scale_to_sharpness_policy);
sharp_level = SPL_NAMESPACE(spl_fixpt_from_fraction(sharpnessX1000, 1000));
/*
* Check if pregen 1dlut table is already precalculated
* If numer/denom is different, then recalculate
*/
if ((filter_isharp_1D_lut_pregen[setup].sharpness_numer == sharpnessX1000) &&
(filter_isharp_1D_lut_pregen[setup].sharpness_denom == 1000))
return;
/*
* Calculate LUT_128_gained with this equation:
*
* LUT_128_gained[i] = (uint8)(0.5 + min(255,(double)(LUT_128[i])*sharpLevel/iGain))
* where LUT_128[i] is contents of 3p0x isharp 1dlut
* where sharpLevel is desired sharpness level
* where iGain is base sharpness level 3.0
* where LUT_128_gained[i] is adjusted 1dlut value based on desired sharpness level
*/
byte_ptr_1dlut_src = (uint8_t *)filter_isharp_1D_lut_3p0x;
byte_ptr_1dlut_dst = (uint8_t *)filter_pregen_store;
size_1dlut = sizeof(filter_isharp_1D_lut_3p0x);
memset(byte_ptr_1dlut_dst, 0, size_1dlut);
for (j = 0; j < size_1dlut; j++) {
sharp_base = spl_fixpt_from_int((int)*byte_ptr_1dlut_src);
sharp_calc = SPL_NAMESPACE(spl_fixpt_mul(sharp_base, sharp_level));
sharp_calc = spl_fixpt_div(sharp_calc, spl_fixpt_from_int(3));
sharp_calc = spl_fixpt_min(spl_fixpt_from_int(255), sharp_calc);
sharp_calc = spl_fixpt_add(sharp_calc,
SPL_NAMESPACE(spl_fixpt_from_fraction(1, 2)));
sharp_calc_int = spl_fixpt_floor(sharp_calc);
/* Clamp it at 0x7F so it doesn't wrap */
if (sharp_calc_int > 127)
sharp_calc_int = 127;
*byte_ptr_1dlut_dst = (uint8_t)sharp_calc_int;
byte_ptr_1dlut_src++;
byte_ptr_1dlut_dst++;
}
/* Update 1dlut table and sharpness level */
memcpy((void *)filter_isharp_1D_lut_pregen[setup].value, (void *)filter_pregen_store, size_1dlut);
filter_isharp_1D_lut_pregen[setup].sharpness_numer = sharpnessX1000;
filter_isharp_1D_lut_pregen[setup].sharpness_denom = 1000;
}
uint32_t *SPL_NAMESPACE(spl_get_pregen_filter_isharp_1D_lut(enum system_setup setup))
{
return filter_isharp_1D_lut_pregen[setup].value;
}
const uint16_t *SPL_NAMESPACE(spl_dscl_get_blur_scale_coeffs_64p(int taps))
{
if (taps == 3)
return filter_isharp_bs_3tap_64p_s1_12;
else if (taps == 4)
return filter_isharp_bs_4tap_64p_s1_12;
else if (taps == 6)
return filter_isharp_bs_4tap_in_6_64p_s1_12;
else {
/* should never happen, bug */
SPL_BREAK_TO_DEBUGGER();
return NULL;
}
}
const uint16_t *SPL_NAMESPACE(spl_dscl_get_blur_scale_coeffs_64p_s1_10(int taps))
{
if (taps == 3)
return filter_isharp_bs_3tap_64p;
else if (taps == 4)
return filter_isharp_bs_4tap_64p;
else if (taps == 6)
return filter_isharp_bs_4tap_in_6_64p;
else {
/* should never happen, bug */
SPL_BREAK_TO_DEBUGGER();
return NULL;
}
}
void SPL_NAMESPACE(spl_set_blur_scale_data(struct dscl_prog_data *dscl_prog_data,
const struct spl_scaler_data *data))
{
dscl_prog_data->filter_blur_scale_h =
SPL_NAMESPACE(spl_dscl_get_blur_scale_coeffs_64p(data->taps.h_taps));
dscl_prog_data->filter_blur_scale_v =
SPL_NAMESPACE(spl_dscl_get_blur_scale_coeffs_64p(data->taps.v_taps));
}
@@ -0,0 +1,44 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2024 Advanced Micro Devices, Inc.
#ifndef __DC_SPL_ISHARP_FILTERS_H__
#define __DC_SPL_ISHARP_FILTERS_H__
#include "dc_spl_types.h"
#define NUM_SHARPNESS_ADJ_LEVELS 6
struct scale_ratio_to_sharpness_level_adj {
unsigned int ratio_numer;
unsigned int ratio_denom;
unsigned int level_down_adj; /* adjust sharpness level down */
};
struct isharp_1D_lut_pregen {
unsigned int sharpness_numer;
unsigned int sharpness_denom;
uint32_t value[ISHARP_LUT_TABLE_SIZE];
};
enum system_setup {
SDR_NL = 0,
SDR_L,
HDR_NL,
HDR_L,
NUM_SHARPNESS_SETUPS
};
void SPL_NAMESPACE(spl_set_blur_scale_data(struct dscl_prog_data *dscl_prog_data,
const struct spl_scaler_data *data));
void SPL_NAMESPACE(spl_build_isharp_1dlut_from_reference_curve(
struct spl_fixed31_32 ratio, enum system_setup setup,
struct adaptive_sharpness sharpness,
enum scale_to_sharpness_policy scale_to_sharpness_policy));
uint32_t *SPL_NAMESPACE(spl_get_pregen_filter_isharp_1D_lut(enum system_setup setup));
// public API
const uint16_t *SPL_NAMESPACE(spl_dscl_get_blur_scale_coeffs_64p(int taps));
const uint16_t *SPL_NAMESPACE(spl_dscl_get_blur_scale_coeffs_64p_s1_10(int taps));
#endif /* __DC_SPL_ISHARP_FILTERS_H__ */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,40 @@
/* SPDX-License-Identifier: MIT */
/* Copyright 2024 Advanced Micro Devices, Inc. */
#ifndef __DC_SPL_SCL_EASF_FILTERS_H__
#define __DC_SPL_SCL_EASF_FILTERS_H__
#include "dc_spl_types.h"
struct scale_ratio_to_reg_value_lookup {
int numer;
int denom;
const uint32_t reg_value;
};
void SPL_NAMESPACE(spl_set_filters_data(struct dscl_prog_data *dscl_prog_data,
const struct spl_scaler_data *data, bool enable_easf_v,
bool enable_easf_h));
uint32_t SPL_NAMESPACE(spl_get_v_bf3_mode(struct spl_fixed31_32 ratio));
uint32_t SPL_NAMESPACE(spl_get_h_bf3_mode(struct spl_fixed31_32 ratio));
uint32_t SPL_NAMESPACE(spl_get_reducer_gain6(int taps, struct spl_fixed31_32 ratio));
uint32_t SPL_NAMESPACE(spl_get_reducer_gain4(int taps, struct spl_fixed31_32 ratio));
uint32_t SPL_NAMESPACE(spl_get_gainRing6(int taps, struct spl_fixed31_32 ratio));
uint32_t SPL_NAMESPACE(spl_get_gainRing4(int taps, struct spl_fixed31_32 ratio));
uint32_t SPL_NAMESPACE(spl_get_3tap_dntilt_uptilt_offset(
int taps, struct spl_fixed31_32 ratio));
uint32_t SPL_NAMESPACE(spl_get_3tap_uptilt_maxval(int taps, struct spl_fixed31_32 ratio));
uint32_t SPL_NAMESPACE(spl_get_3tap_dntilt_slope(int taps, struct spl_fixed31_32 ratio));
uint32_t SPL_NAMESPACE(spl_get_3tap_uptilt1_slope(int taps, struct spl_fixed31_32 ratio));
uint32_t SPL_NAMESPACE(spl_get_3tap_uptilt2_slope(int taps, struct spl_fixed31_32 ratio));
uint32_t SPL_NAMESPACE(spl_get_3tap_uptilt2_offset(int taps, struct spl_fixed31_32 ratio));
/* public API */
const uint16_t *SPL_NAMESPACE(spl_dscl_get_easf_filter_coeffs_64p(
int taps, struct spl_fixed31_32 ratio));
const uint16_t *SPL_NAMESPACE(spl_dscl_get_easf_filter_coeffs_64p_s1_10(
int taps, struct spl_fixed31_32 ratio));
#endif /* __DC_SPL_SCL_EASF_FILTERS_H__ */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,14 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2024 Advanced Micro Devices, Inc.
#ifndef __DC_SPL_SCL_FILTERS_H__
#define __DC_SPL_SCL_FILTERS_H__
#include "dc_spl_types.h"
/* public API */
const uint16_t *SPL_NAMESPACE(spl_dscl_get_filter_coeffs_64p(
int taps, struct spl_fixed31_32 ratio));
#endif /* __DC_SPL_SCL_FILTERS_H__ */
@@ -0,0 +1,560 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2024 Advanced Micro Devices, Inc.
#ifndef __DC_SPL_TYPES_H__
#define __DC_SPL_TYPES_H__
#include "spl_debug.h"
#include "spl_os_types.h" // swap
#include "spl_fixpt31_32.h" // fixed31_32 and related functions
#include "spl_custom_float.h" // custom float and related functions
struct spl_size {
uint32_t width;
uint32_t height;
};
struct spl_rect {
int x;
int y;
int width;
int height;
};
struct spl_ratios {
struct spl_fixed31_32 horz;
struct spl_fixed31_32 vert;
struct spl_fixed31_32 horz_c;
struct spl_fixed31_32 vert_c;
};
struct spl_inits {
struct spl_fixed31_32 h;
struct spl_fixed31_32 h_c;
struct spl_fixed31_32 v;
struct spl_fixed31_32 v_c;
};
struct spl_taps {
uint32_t v_taps;
uint32_t h_taps;
uint32_t v_taps_c;
uint32_t h_taps_c;
bool integer_scaling;
};
enum spl_view_3d {
SPL_VIEW_3D_NONE = 0,
SPL_VIEW_3D_FRAME_SEQUENTIAL,
SPL_VIEW_3D_SIDE_BY_SIDE,
SPL_VIEW_3D_TOP_AND_BOTTOM,
SPL_VIEW_3D_COUNT,
SPL_VIEW_3D_FIRST = SPL_VIEW_3D_FRAME_SEQUENTIAL
};
/* Pixel format */
enum spl_pixel_format {
/*graph*/
SPL_PIXEL_FORMAT_UNINITIALIZED,
SPL_PIXEL_FORMAT_INDEX8,
SPL_PIXEL_FORMAT_RGB565,
SPL_PIXEL_FORMAT_ARGB8888,
SPL_PIXEL_FORMAT_ARGB2101010,
SPL_PIXEL_FORMAT_ARGB2101010_XRBIAS,
SPL_PIXEL_FORMAT_FP16,
/*video*/
SPL_PIXEL_FORMAT_420BPP8,
SPL_PIXEL_FORMAT_420BPP10,
/*end of pixel format definition*/
SPL_PIXEL_FORMAT_GRPH_BEGIN = SPL_PIXEL_FORMAT_INDEX8,
SPL_PIXEL_FORMAT_GRPH_END = SPL_PIXEL_FORMAT_FP16,
SPL_PIXEL_FORMAT_SUBSAMPLED_BEGIN = SPL_PIXEL_FORMAT_420BPP8,
SPL_PIXEL_FORMAT_SUBSAMPLED_END = SPL_PIXEL_FORMAT_420BPP10,
SPL_PIXEL_FORMAT_VIDEO_BEGIN = SPL_PIXEL_FORMAT_420BPP8,
SPL_PIXEL_FORMAT_VIDEO_END = SPL_PIXEL_FORMAT_420BPP10,
SPL_PIXEL_FORMAT_INVALID,
SPL_PIXEL_FORMAT_UNKNOWN
};
enum lb_memory_config {
/* Enable all 3 pieces of memory */
LB_MEMORY_CONFIG_0 = 0,
/* Enable only the first piece of memory */
LB_MEMORY_CONFIG_1 = 1,
/* Enable only the second piece of memory */
LB_MEMORY_CONFIG_2 = 2,
/* Only applicable in 4:2:0 mode, enable all 3 pieces of memory and the
* last piece of chroma memory used for the luma storage
*/
LB_MEMORY_CONFIG_3 = 3
};
/* Rotation angle */
enum spl_rotation_angle {
SPL_ROTATION_ANGLE_0 = 0,
SPL_ROTATION_ANGLE_90,
SPL_ROTATION_ANGLE_180,
SPL_ROTATION_ANGLE_270,
SPL_ROTATION_ANGLE_COUNT
};
enum spl_color_space {
SPL_COLOR_SPACE_UNKNOWN,
SPL_COLOR_SPACE_SRGB,
SPL_COLOR_SPACE_XR_RGB,
SPL_COLOR_SPACE_SRGB_LIMITED,
SPL_COLOR_SPACE_MSREF_SCRGB,
SPL_COLOR_SPACE_YCBCR601,
SPL_COLOR_SPACE_YCBCR709,
SPL_COLOR_SPACE_XV_YCC_709,
SPL_COLOR_SPACE_XV_YCC_601,
SPL_COLOR_SPACE_YCBCR601_LIMITED,
SPL_COLOR_SPACE_YCBCR709_LIMITED,
SPL_COLOR_SPACE_2020_RGB_FULLRANGE,
SPL_COLOR_SPACE_2020_RGB_LIMITEDRANGE,
SPL_COLOR_SPACE_2020_YCBCR,
SPL_COLOR_SPACE_ADOBERGB,
SPL_COLOR_SPACE_DCIP3,
SPL_COLOR_SPACE_DISPLAYNATIVE,
SPL_COLOR_SPACE_DOLBYVISION,
SPL_COLOR_SPACE_APPCTRL,
SPL_COLOR_SPACE_CUSTOMPOINTS,
SPL_COLOR_SPACE_YCBCR709_BLACK,
};
enum chroma_cositing {
CHROMA_COSITING_NONE,
CHROMA_COSITING_LEFT,
CHROMA_COSITING_TOPLEFT,
CHROMA_COSITING_COUNT
};
// Scratch space for calculating scaler params
struct spl_scaler_data {
int h_active;
int v_active;
struct spl_taps taps;
struct spl_rect viewport;
struct spl_rect viewport_c;
struct spl_rect recout;
struct spl_ratios ratios;
struct spl_ratios recip_ratios;
struct spl_inits inits;
};
enum spl_transfer_func_type {
SPL_TF_TYPE_PREDEFINED,
SPL_TF_TYPE_DISTRIBUTED_POINTS,
SPL_TF_TYPE_BYPASS,
SPL_TF_TYPE_HWPWL
};
enum spl_transfer_func_predefined {
SPL_TRANSFER_FUNCTION_SRGB,
SPL_TRANSFER_FUNCTION_BT709,
SPL_TRANSFER_FUNCTION_PQ,
SPL_TRANSFER_FUNCTION_LINEAR,
SPL_TRANSFER_FUNCTION_UNITY,
SPL_TRANSFER_FUNCTION_HLG,
SPL_TRANSFER_FUNCTION_HLG12,
SPL_TRANSFER_FUNCTION_GAMMA22,
SPL_TRANSFER_FUNCTION_GAMMA24,
SPL_TRANSFER_FUNCTION_GAMMA26
};
/*==============================================================*/
/* Below structs are defined to hold hw register data */
// SPL output is used to set below registers
// MPC_SIZE - set based on scl_data h_active and v_active
struct mpc_size {
uint32_t width;
uint32_t height;
};
// SCL_MODE - set based on scl_data.ratios and always_scale
enum scl_mode {
SCL_MODE_SCALING_444_BYPASS = 0,
SCL_MODE_SCALING_444_RGB_ENABLE = 1,
SCL_MODE_SCALING_444_YCBCR_ENABLE = 2,
SCL_MODE_SCALING_420_YCBCR_ENABLE = 3,
SCL_MODE_SCALING_420_LUMA_BYPASS = 4,
SCL_MODE_SCALING_420_CHROMA_BYPASS = 5,
SCL_MODE_DSCL_BYPASS = 6
};
// SCL_BLACK_COLOR - set based on scl_data.format
struct scl_black_color {
uint32_t offset_rgb_y;
uint32_t offset_rgb_cbcr;
};
// RATIO - set based on scl_data.ratios
struct ratio {
uint32_t h_scale_ratio;
uint32_t v_scale_ratio;
uint32_t h_scale_ratio_c;
uint32_t v_scale_ratio_c;
};
// INIT - set based on scl_data.init
struct init {
// SCL_HORZ_FILTER_INIT
uint32_t h_filter_init_frac; // SCL_H_INIT_FRAC
uint32_t h_filter_init_int; // SCL_H_INIT_INT
// SCL_HORZ_FILTER_INIT_C
uint32_t h_filter_init_frac_c; // SCL_H_INIT_FRAC_C
uint32_t h_filter_init_int_c; // SCL_H_INIT_INT_C
// SCL_VERT_FILTER_INIT
uint32_t v_filter_init_frac; // SCL_V_INIT_FRAC
uint32_t v_filter_init_int; // SCL_V_INIT_INT
// SCL_VERT_FILTER_INIT_C
uint32_t v_filter_init_frac_c; // SCL_V_INIT_FRAC_C
uint32_t v_filter_init_int_c; // SCL_V_INIT_INT_C
// SCL_VERT_FILTER_INIT_BOT
uint32_t v_filter_init_bot_frac; // SCL_V_INIT_FRAC_BOT
uint32_t v_filter_init_bot_int; // SCL_V_INIT_INT_BOT
// SCL_VERT_FILTER_INIT_BOT_C
uint32_t v_filter_init_bot_frac_c; // SCL_V_INIT_FRAC_BOT_C
uint32_t v_filter_init_bot_int_c; // SCL_V_INIT_INT_BOT_C
};
// FILTER - calculated based on scl_data ratios and taps
// iSHARP
struct isharp_noise_det {
uint32_t enable; // ISHARP_NOISEDET_EN
uint32_t mode; // ISHARP_NOISEDET_MODE
uint32_t uthreshold; // ISHARP_NOISEDET_UTHRE
uint32_t dthreshold; // ISHARP_NOISEDET_DTHRE
uint32_t pwl_start_in; // ISHARP_NOISEDET_PWL_START_IN
uint32_t pwl_end_in; // ISHARP_NOISEDET_PWL_END_IN
uint32_t pwl_slope; // ISHARP_NOISEDET_PWL_SLOPE
};
struct isharp_lba {
uint32_t mode; // ISHARP_LBA_MODE
uint32_t in_seg[6];
uint32_t base_seg[6];
uint32_t slope_seg[6];
};
struct isharp_fmt {
uint32_t mode; // ISHARP_FMT_MODE
uint32_t norm; // ISHARP_FMT_NORM
};
struct isharp_nldelta_sclip {
uint32_t enable_p; // ISHARP_NLDELTA_SCLIP_EN_P
uint32_t pivot_p; // ISHARP_NLDELTA_SCLIP_PIVOT_P
uint32_t slope_p; // ISHARP_NLDELTA_SCLIP_SLOPE_P
uint32_t enable_n; // ISHARP_NLDELTA_SCLIP_EN_N
uint32_t pivot_n; // ISHARP_NLDELTA_SCLIP_PIVOT_N
uint32_t slope_n; // ISHARP_NLDELTA_SCLIP_SLOPE_N
};
enum isharp_en {
ISHARP_DISABLE,
ISHARP_ENABLE
};
#define ISHARP_LUT_TABLE_SIZE 32
// Below struct holds values that can be directly used to program
// hardware registers. No conversion/clamping is required
struct dscl_prog_data {
struct spl_rect recout; // RECOUT - set based on scl_data.recout
struct mpc_size mpc_size;
uint32_t dscl_mode;
struct scl_black_color scl_black_color;
struct ratio ratios;
struct init init;
struct spl_taps taps; // TAPS - set based on scl_data.taps
struct spl_rect viewport;
struct spl_rect viewport_c;
// raw filter
const uint16_t *filter_h;
const uint16_t *filter_v;
const uint16_t *filter_h_c;
const uint16_t *filter_v_c;
// EASF registers
uint32_t easf_matrix_mode;
uint32_t easf_ltonl_en;
uint32_t easf_v_en;
uint32_t easf_v_sharp_factor;
uint32_t easf_v_ring;
uint32_t easf_v_bf1_en;
uint32_t easf_v_bf2_mode;
uint32_t easf_v_bf3_mode;
uint32_t easf_v_bf2_flat1_gain;
uint32_t easf_v_bf2_flat2_gain;
uint32_t easf_v_bf2_roc_gain;
uint32_t easf_v_ringest_3tap_dntilt_uptilt;
uint32_t easf_v_ringest_3tap_uptilt_max;
uint32_t easf_v_ringest_3tap_dntilt_slope;
uint32_t easf_v_ringest_3tap_uptilt1_slope;
uint32_t easf_v_ringest_3tap_uptilt2_slope;
uint32_t easf_v_ringest_3tap_uptilt2_offset;
uint32_t easf_v_ringest_eventap_reduceg1;
uint32_t easf_v_ringest_eventap_reduceg2;
uint32_t easf_v_ringest_eventap_gain1;
uint32_t easf_v_ringest_eventap_gain2;
uint32_t easf_v_bf_maxa;
uint32_t easf_v_bf_maxb;
uint32_t easf_v_bf_mina;
uint32_t easf_v_bf_minb;
uint32_t easf_v_bf1_pwl_in_seg0;
uint32_t easf_v_bf1_pwl_base_seg0;
uint32_t easf_v_bf1_pwl_slope_seg0;
uint32_t easf_v_bf1_pwl_in_seg1;
uint32_t easf_v_bf1_pwl_base_seg1;
uint32_t easf_v_bf1_pwl_slope_seg1;
uint32_t easf_v_bf1_pwl_in_seg2;
uint32_t easf_v_bf1_pwl_base_seg2;
uint32_t easf_v_bf1_pwl_slope_seg2;
uint32_t easf_v_bf1_pwl_in_seg3;
uint32_t easf_v_bf1_pwl_base_seg3;
uint32_t easf_v_bf1_pwl_slope_seg3;
uint32_t easf_v_bf1_pwl_in_seg4;
uint32_t easf_v_bf1_pwl_base_seg4;
uint32_t easf_v_bf1_pwl_slope_seg4;
uint32_t easf_v_bf1_pwl_in_seg5;
uint32_t easf_v_bf1_pwl_base_seg5;
uint32_t easf_v_bf1_pwl_slope_seg5;
uint32_t easf_v_bf1_pwl_in_seg6;
uint32_t easf_v_bf1_pwl_base_seg6;
uint32_t easf_v_bf1_pwl_slope_seg6;
uint32_t easf_v_bf1_pwl_in_seg7;
uint32_t easf_v_bf1_pwl_base_seg7;
uint32_t easf_v_bf3_pwl_in_set0;
uint32_t easf_v_bf3_pwl_base_set0;
uint32_t easf_v_bf3_pwl_slope_set0;
uint32_t easf_v_bf3_pwl_in_set1;
uint32_t easf_v_bf3_pwl_base_set1;
uint32_t easf_v_bf3_pwl_slope_set1;
uint32_t easf_v_bf3_pwl_in_set2;
uint32_t easf_v_bf3_pwl_base_set2;
uint32_t easf_v_bf3_pwl_slope_set2;
uint32_t easf_v_bf3_pwl_in_set3;
uint32_t easf_v_bf3_pwl_base_set3;
uint32_t easf_v_bf3_pwl_slope_set3;
uint32_t easf_v_bf3_pwl_in_set4;
uint32_t easf_v_bf3_pwl_base_set4;
uint32_t easf_v_bf3_pwl_slope_set4;
uint32_t easf_v_bf3_pwl_in_set5;
uint32_t easf_v_bf3_pwl_base_set5;
uint32_t easf_h_en;
uint32_t easf_h_sharp_factor;
uint32_t easf_h_ring;
uint32_t easf_h_bf1_en;
uint32_t easf_h_bf2_mode;
uint32_t easf_h_bf3_mode;
uint32_t easf_h_bf2_flat1_gain;
uint32_t easf_h_bf2_flat2_gain;
uint32_t easf_h_bf2_roc_gain;
uint32_t easf_h_ringest_eventap_reduceg1;
uint32_t easf_h_ringest_eventap_reduceg2;
uint32_t easf_h_ringest_eventap_gain1;
uint32_t easf_h_ringest_eventap_gain2;
uint32_t easf_h_bf_maxa;
uint32_t easf_h_bf_maxb;
uint32_t easf_h_bf_mina;
uint32_t easf_h_bf_minb;
uint32_t easf_h_bf1_pwl_in_seg0;
uint32_t easf_h_bf1_pwl_base_seg0;
uint32_t easf_h_bf1_pwl_slope_seg0;
uint32_t easf_h_bf1_pwl_in_seg1;
uint32_t easf_h_bf1_pwl_base_seg1;
uint32_t easf_h_bf1_pwl_slope_seg1;
uint32_t easf_h_bf1_pwl_in_seg2;
uint32_t easf_h_bf1_pwl_base_seg2;
uint32_t easf_h_bf1_pwl_slope_seg2;
uint32_t easf_h_bf1_pwl_in_seg3;
uint32_t easf_h_bf1_pwl_base_seg3;
uint32_t easf_h_bf1_pwl_slope_seg3;
uint32_t easf_h_bf1_pwl_in_seg4;
uint32_t easf_h_bf1_pwl_base_seg4;
uint32_t easf_h_bf1_pwl_slope_seg4;
uint32_t easf_h_bf1_pwl_in_seg5;
uint32_t easf_h_bf1_pwl_base_seg5;
uint32_t easf_h_bf1_pwl_slope_seg5;
uint32_t easf_h_bf1_pwl_in_seg6;
uint32_t easf_h_bf1_pwl_base_seg6;
uint32_t easf_h_bf1_pwl_slope_seg6;
uint32_t easf_h_bf1_pwl_in_seg7;
uint32_t easf_h_bf1_pwl_base_seg7;
uint32_t easf_h_bf3_pwl_in_set0;
uint32_t easf_h_bf3_pwl_base_set0;
uint32_t easf_h_bf3_pwl_slope_set0;
uint32_t easf_h_bf3_pwl_in_set1;
uint32_t easf_h_bf3_pwl_base_set1;
uint32_t easf_h_bf3_pwl_slope_set1;
uint32_t easf_h_bf3_pwl_in_set2;
uint32_t easf_h_bf3_pwl_base_set2;
uint32_t easf_h_bf3_pwl_slope_set2;
uint32_t easf_h_bf3_pwl_in_set3;
uint32_t easf_h_bf3_pwl_base_set3;
uint32_t easf_h_bf3_pwl_slope_set3;
uint32_t easf_h_bf3_pwl_in_set4;
uint32_t easf_h_bf3_pwl_base_set4;
uint32_t easf_h_bf3_pwl_slope_set4;
uint32_t easf_h_bf3_pwl_in_set5;
uint32_t easf_h_bf3_pwl_base_set5;
uint32_t easf_matrix_c0;
uint32_t easf_matrix_c1;
uint32_t easf_matrix_c2;
uint32_t easf_matrix_c3;
// iSharp
uint32_t isharp_en; // ISHARP_EN
struct isharp_noise_det isharp_noise_det; // ISHARP_NOISEDET
uint32_t isharp_nl_en; // ISHARP_NL_EN ? TODO:check this
struct isharp_lba isharp_lba; // ISHARP_LBA
struct isharp_fmt isharp_fmt; // ISHARP_FMT
uint32_t isharp_delta[ISHARP_LUT_TABLE_SIZE];
struct isharp_nldelta_sclip isharp_nldelta_sclip; // ISHARP_NLDELTA_SCLIP
/* blur and scale filter */
const uint16_t *filter_blur_scale_v;
const uint16_t *filter_blur_scale_h;
int sharpness_level; /* Track sharpness level */
};
/* SPL input and output definitions */
// SPL scratch struct
struct spl_scratch {
// Pack all SPL outputs in scl_data
struct spl_scaler_data scl_data;
};
/* SPL input and output definitions */
// SPL outputs struct
struct spl_out {
// Pack all output need to program hw registers
struct dscl_prog_data *dscl_prog_data;
};
// end of SPL outputs
// SPL inputs
// opp extra adjustment for rect
struct spl_opp_adjust {
int x;
int y;
int width;
int height;
};
// Basic input information
struct basic_in {
enum spl_pixel_format format; // Pixel Format
enum chroma_cositing cositing; /* Chroma Subsampling Offset */
struct spl_rect src_rect; // Source rect
struct spl_rect dst_rect; // Destination Rect
struct spl_rect clip_rect; // Clip rect
enum spl_rotation_angle rotation; // Rotation
bool horizontal_mirror; // Horizontal mirror
struct { // previous mpc_combine_h - split count
bool use_recout_width_aligned;
union {
int mpc_num_h_slices;
int mpc_recout_width_align;
} num_slices_recout_width;
} num_h_slices_recout_width_align;
int mpc_h_slice_index; // previous mpc_combine_v - split_idx
struct spl_opp_adjust opp_recout_adjust;
// Inputs for adaptive scaler - TODO
enum spl_transfer_func_type tf_type; /* Transfer function type */
enum spl_transfer_func_predefined tf_predefined_type; /* Transfer function predefined type */
// enum dc_transfer_func_predefined tf;
enum spl_color_space color_space; // Color Space
unsigned int max_luminance; // Max Luminance TODO: Is determined in dc_hw_sequencer.c is_sdr
bool film_grain_applied; // Film Grain Applied // TODO: To check from where to get this?
int custom_width; // Width for non-standard segmentation - used when != 0
int custom_x; // Start x for non-standard segmentation - used when custom_width != 0
};
// Basic output information
struct basic_out {
struct spl_size output_size; // Output Size
struct spl_rect dst_rect; // Destination Rect
struct spl_rect src_rect; // Source rect
int odm_combine_factor; // deprecated
struct spl_rect odm_slice_rect; // OPP input rect in timing active
enum spl_view_3d view_format; // TODO: View format Check if it is chroma subsampling
bool always_scale; // Is always scale enabled? Required for getting SCL_MODE
int max_downscale_src_width; // Required to get optimal no of taps
bool alpha_en;
bool use_two_pixels_per_container;
};
enum sharpness_setting {
SHARPNESS_HW_OFF = 0,
SHARPNESS_ZERO,
SHARPNESS_CUSTOM
};
enum sharpness_range_source {
SHARPNESS_RANGE_DCN = 0,
SHARPNESS_RANGE_DCN_OVERRIDE
};
struct spl_sharpness_range {
int sdr_rgb_min;
int sdr_rgb_max;
int sdr_rgb_mid;
int sdr_yuv_min;
int sdr_yuv_max;
int sdr_yuv_mid;
int hdr_rgb_min;
int hdr_rgb_max;
int hdr_rgb_mid;
};
struct adaptive_sharpness {
bool enable;
unsigned int sharpness_level;
struct spl_sharpness_range sharpness_range;
};
enum linear_light_scaling { // convert it in translation logic
LLS_PREF_DONT_CARE = 0,
LLS_PREF_YES,
LLS_PREF_NO
};
enum sharpen_policy {
SHARPEN_ALWAYS = 0,
SHARPEN_YUV = 1,
SHARPEN_RGB_FULLSCREEN_YUV = 2,
SHARPEN_FULLSCREEN_ALL = 3
};
enum scale_to_sharpness_policy {
NO_SCALE_TO_SHARPNESS_ADJ = 0,
SCALE_TO_SHARPNESS_ADJ_YUV = 1,
SCALE_TO_SHARPNESS_ADJ_ALL = 2
};
struct spl_callbacks {
void (*spl_calc_lb_num_partitions)
(bool alpha_en,
const struct spl_scaler_data *scl_data,
enum lb_memory_config lb_config,
int *num_part_y,
int *num_part_c);
};
struct spl_debug {
int visual_confirm_base_offset;
int visual_confirm_dpp_offset;
enum scale_to_sharpness_policy scale_to_sharpness_policy;
};
struct spl_in {
struct basic_out basic_out;
struct basic_in basic_in;
// Basic slice information
int odm_slice_index; // ODM Slice Index using get_odm_split_index
struct spl_taps scaling_quality; // Explicit Scaling Quality
struct spl_callbacks callbacks;
// Inputs for isharp and EASF
struct adaptive_sharpness adaptive_sharpness; // Adaptive Sharpness
enum linear_light_scaling lls_pref; // Linear Light Scaling
bool prefer_easf;
bool disable_easf;
bool override_easf; /* If true, keep EASF enabled but use provided in_taps */
struct spl_debug debug;
bool is_fullscreen;
bool is_hdr_on;
int h_active;
int v_active;
int min_viewport_size;
int sdr_white_level_nits;
enum sharpen_policy sharpen_policy;
};
// end of SPL inputs
#endif /* __DC_SPL_TYPES_H__ */
@@ -0,0 +1,152 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2024 Advanced Micro Devices, Inc.
#include "spl_debug.h"
#include "spl_custom_float.h"
static bool spl_build_custom_float(struct spl_fixed31_32 value,
const struct spl_custom_float_format *format,
bool *negative,
uint32_t *mantissa,
uint32_t *exponenta)
{
uint32_t exp_offset = (1 << (format->exponenta_bits - 1)) - 1;
const struct spl_fixed31_32 mantissa_constant_plus_max_fraction =
SPL_NAMESPACE(spl_fixpt_from_fraction((1LL << (format->mantissa_bits + 1)) - 1,
1LL << format->mantissa_bits));
struct spl_fixed31_32 mantiss;
if (spl_fixpt_eq(value, spl_fixpt_zero)) {
*negative = false;
*mantissa = 0;
*exponenta = 0;
return true;
}
if (spl_fixpt_lt(value, spl_fixpt_zero)) {
*negative = format->sign;
value = spl_fixpt_neg(value);
} else {
*negative = false;
}
if (spl_fixpt_lt(value, spl_fixpt_one)) {
uint32_t i = 1;
do {
value = spl_fixpt_shl(value, 1);
++i;
} while (spl_fixpt_lt(value, spl_fixpt_one));
--i;
if (exp_offset <= i) {
*mantissa = 0;
*exponenta = 0;
return true;
}
*exponenta = exp_offset - i;
} else if (spl_fixpt_le(mantissa_constant_plus_max_fraction, value)) {
uint32_t i = 1;
do {
value = spl_fixpt_shr(value, 1);
++i;
} while (spl_fixpt_lt(mantissa_constant_plus_max_fraction, value));
*exponenta = exp_offset + i - 1;
} else {
*exponenta = exp_offset;
}
mantiss = spl_fixpt_sub(value, spl_fixpt_one);
if (spl_fixpt_lt(mantiss, spl_fixpt_zero) ||
spl_fixpt_lt(spl_fixpt_one, mantiss))
mantiss = spl_fixpt_zero;
else
mantiss = spl_fixpt_shl(mantiss, format->mantissa_bits);
*mantissa = spl_fixpt_floor(mantiss);
return true;
}
static bool spl_setup_custom_float(const struct spl_custom_float_format *format,
bool negative,
uint32_t mantissa,
uint32_t exponenta,
uint32_t *result)
{
uint32_t i = 0;
uint32_t j = 0;
uint32_t value = 0;
/* verification code:
* once calculation is ok we can remove it
*/
const uint32_t mantissa_mask =
(1 << (format->mantissa_bits + 1)) - 1;
const uint32_t exponenta_mask =
(1 << (format->exponenta_bits + 1)) - 1;
if (mantissa & ~mantissa_mask) {
SPL_BREAK_TO_DEBUGGER();
mantissa = mantissa_mask;
}
if (exponenta & ~exponenta_mask) {
SPL_BREAK_TO_DEBUGGER();
exponenta = exponenta_mask;
}
/* end of verification code */
while (i < format->mantissa_bits) {
uint32_t mask = 1 << i;
if (mantissa & mask)
value |= mask;
++i;
}
while (j < format->exponenta_bits) {
uint32_t mask = 1 << j;
if (exponenta & mask)
value |= mask << i;
++j;
}
if (negative && format->sign)
value |= 1 << (i + j);
*result = value;
return true;
}
bool SPL_NAMESPACE(spl_convert_to_custom_float_format(
struct spl_fixed31_32 value,
const struct spl_custom_float_format *format,
uint32_t *result))
{
uint32_t mantissa;
uint32_t exponenta;
bool negative;
return spl_build_custom_float(value, format, &negative, &mantissa, &exponenta) &&
spl_setup_custom_float(format,
negative,
mantissa,
exponenta,
result);
}
@@ -0,0 +1,29 @@
/* SPDX-License-Identifier: MIT */
/* Copyright 2024 Advanced Micro Devices, Inc. */
#ifndef SPL_CUSTOM_FLOAT_H_
#define SPL_CUSTOM_FLOAT_H_
#include "spl_os_types.h"
#include "spl_fixpt31_32.h"
struct spl_custom_float_format {
uint32_t mantissa_bits;
uint32_t exponenta_bits;
bool sign;
};
struct spl_custom_float_value {
uint32_t mantissa;
uint32_t exponenta;
uint32_t value;
bool negative;
};
bool SPL_NAMESPACE(spl_convert_to_custom_float_format(
struct spl_fixed31_32 value,
const struct spl_custom_float_format *format,
uint32_t *result));
#endif //SPL_CUSTOM_FLOAT_H_
@@ -0,0 +1,30 @@
/* SPDX-License-Identifier: MIT */
/* Copyright 2024 Advanced Micro Devices, Inc. */
#ifndef SPL_DEBUG_H
#define SPL_DEBUG_H
#if defined(CONFIG_HAVE_KGDB) || defined(CONFIG_KGDB)
#define SPL_ASSERT_CRITICAL(expr) do { \
if (WARN_ON(!(expr))) { \
kgdb_breakpoint(); \
} \
} while (0)
#else
#define SPL_ASSERT_CRITICAL(expr) do { \
if (WARN_ON(!(expr))) { \
; \
} \
} while (0)
#endif /* CONFIG_HAVE_KGDB || CONFIG_KGDB */
#if defined(CONFIG_DEBUG_KERNEL_DC)
#define SPL_ASSERT(expr) SPL_ASSERT_CRITICAL(expr)
#else
#define SPL_ASSERT(expr) WARN_ON(!(expr))
#endif /* CONFIG_DEBUG_KERNEL_DC */
#define SPL_BREAK_TO_DEBUGGER() SPL_ASSERT(0)
#endif // SPL_DEBUG_H
@@ -0,0 +1,495 @@
// SPDX-License-Identifier: MIT
//
// Copyright 2024 Advanced Micro Devices, Inc.
#include "spl_fixpt31_32.h"
static const struct spl_fixed31_32 spl_fixpt_two_pi = { 26986075409LL };
static const struct spl_fixed31_32 spl_fixpt_ln2 = { 2977044471LL };
static const struct spl_fixed31_32 spl_fixpt_ln2_div_2 = { 1488522236LL };
static inline unsigned long long abs_i64(
long long arg)
{
if (arg > 0)
return (unsigned long long)arg;
else
return (unsigned long long)(-arg);
}
/*
* @brief
* result = dividend / divisor
* *remainder = dividend % divisor
*/
static inline unsigned long long spl_complete_integer_division_u64(
unsigned long long dividend,
unsigned long long divisor,
unsigned long long *remainder)
{
unsigned long long result;
result = spl_div64_u64_rem(dividend, divisor, remainder);
return result;
}
#define FRACTIONAL_PART_MASK \
((1ULL << FIXED31_32_BITS_PER_FRACTIONAL_PART) - 1)
#define GET_INTEGER_PART(x) \
((x) >> FIXED31_32_BITS_PER_FRACTIONAL_PART)
#define GET_FRACTIONAL_PART(x) \
(FRACTIONAL_PART_MASK & (x))
struct spl_fixed31_32 SPL_NAMESPACE(spl_fixpt_from_fraction(
long long numerator, long long denominator))
{
struct spl_fixed31_32 res;
bool arg1_negative = numerator < 0;
bool arg2_negative = denominator < 0;
unsigned long long arg1_value = arg1_negative ? -numerator : numerator;
unsigned long long arg2_value = arg2_negative ? -denominator : denominator;
unsigned long long remainder;
/* determine integer part */
unsigned long long res_value = spl_complete_integer_division_u64(
arg1_value, arg2_value, &remainder);
SPL_ASSERT(res_value <= (unsigned long long)LONG_MAX);
/* determine fractional part */
{
unsigned int i = FIXED31_32_BITS_PER_FRACTIONAL_PART;
do {
remainder <<= 1;
res_value <<= 1;
if (remainder >= arg2_value) {
res_value |= 1;
remainder -= arg2_value;
}
} while (--i != 0);
}
/* round up LSB */
{
unsigned long long summand = (remainder << 1) >= arg2_value;
SPL_ASSERT(res_value <= (unsigned long long)LLONG_MAX - summand);
res_value += summand;
}
res.value = (long long)res_value;
if (arg1_negative ^ arg2_negative)
res.value = -res.value;
return res;
}
struct spl_fixed31_32 SPL_NAMESPACE(spl_fixpt_mul(
struct spl_fixed31_32 arg1, struct spl_fixed31_32 arg2))
{
struct spl_fixed31_32 res;
bool arg1_negative = arg1.value < 0;
bool arg2_negative = arg2.value < 0;
unsigned long long arg1_value = arg1_negative ? -arg1.value : arg1.value;
unsigned long long arg2_value = arg2_negative ? -arg2.value : arg2.value;
unsigned long long arg1_int = GET_INTEGER_PART(arg1_value);
unsigned long long arg2_int = GET_INTEGER_PART(arg2_value);
unsigned long long arg1_fra = GET_FRACTIONAL_PART(arg1_value);
unsigned long long arg2_fra = GET_FRACTIONAL_PART(arg2_value);
unsigned long long tmp;
res.value = arg1_int * arg2_int;
SPL_ASSERT(res.value <= (long long)LONG_MAX);
res.value <<= FIXED31_32_BITS_PER_FRACTIONAL_PART;
tmp = arg1_int * arg2_fra;
SPL_ASSERT(tmp <= (unsigned long long)(LLONG_MAX - res.value));
res.value += tmp;
tmp = arg2_int * arg1_fra;
SPL_ASSERT(tmp <= (unsigned long long)(LLONG_MAX - res.value));
res.value += tmp;
tmp = arg1_fra * arg2_fra;
tmp = (tmp >> FIXED31_32_BITS_PER_FRACTIONAL_PART) +
(tmp >= (unsigned long long)spl_fixpt_half.value);
SPL_ASSERT(tmp <= (unsigned long long)(LLONG_MAX - res.value));
res.value += tmp;
if (arg1_negative ^ arg2_negative)
res.value = -res.value;
return res;
}
struct spl_fixed31_32 SPL_NAMESPACE(spl_fixpt_sqr(struct spl_fixed31_32 arg))
{
struct spl_fixed31_32 res;
unsigned long long arg_value = abs_i64(arg.value);
unsigned long long arg_int = GET_INTEGER_PART(arg_value);
unsigned long long arg_fra = GET_FRACTIONAL_PART(arg_value);
unsigned long long tmp;
res.value = arg_int * arg_int;
SPL_ASSERT(res.value <= (long long)LONG_MAX);
res.value <<= FIXED31_32_BITS_PER_FRACTIONAL_PART;
tmp = arg_int * arg_fra;
SPL_ASSERT(tmp <= (unsigned long long)(LLONG_MAX - res.value));
res.value += tmp;
SPL_ASSERT(tmp <= (unsigned long long)(LLONG_MAX - res.value));
res.value += tmp;
tmp = arg_fra * arg_fra;
tmp = (tmp >> FIXED31_32_BITS_PER_FRACTIONAL_PART) +
(tmp >= (unsigned long long)spl_fixpt_half.value);
SPL_ASSERT(tmp <= (unsigned long long)(LLONG_MAX - res.value));
res.value += tmp;
return res;
}
struct spl_fixed31_32 SPL_NAMESPACE(spl_fixpt_recip(struct spl_fixed31_32 arg))
{
/*
* @note
* Good idea to use Newton's method
*/
return SPL_NAMESPACE(spl_fixpt_from_fraction(
spl_fixpt_one.value,
arg.value));
}
struct spl_fixed31_32 SPL_NAMESPACE(spl_fixpt_sinc(struct spl_fixed31_32 arg))
{
struct spl_fixed31_32 square;
struct spl_fixed31_32 res = spl_fixpt_one;
int n = 27;
struct spl_fixed31_32 arg_norm = arg;
if (spl_fixpt_le(
spl_fixpt_two_pi,
spl_fixpt_abs(arg))) {
arg_norm = spl_fixpt_sub(
arg_norm,
spl_fixpt_mul_int(
spl_fixpt_two_pi,
(int)spl_div64_s64(
arg_norm.value,
spl_fixpt_two_pi.value)));
}
square = SPL_NAMESPACE(spl_fixpt_sqr(arg_norm));
do {
res = spl_fixpt_sub(
spl_fixpt_one,
spl_fixpt_div_int(
SPL_NAMESPACE(spl_fixpt_mul(
square,
res)),
n * (n - 1)));
n -= 2;
} while (n > 2);
if (arg.value != arg_norm.value)
res = spl_fixpt_div(
SPL_NAMESPACE(spl_fixpt_mul(res, arg_norm)),
arg);
return res;
}
struct spl_fixed31_32 SPL_NAMESPACE(spl_fixpt_sin(struct spl_fixed31_32 arg))
{
return SPL_NAMESPACE(spl_fixpt_mul(
arg,
SPL_NAMESPACE(spl_fixpt_sinc(arg))));
}
struct spl_fixed31_32 SPL_NAMESPACE(spl_fixpt_cos(struct spl_fixed31_32 arg))
{
/* TODO implement argument normalization */
const struct spl_fixed31_32 square = SPL_NAMESPACE(spl_fixpt_sqr(arg));
struct spl_fixed31_32 res = spl_fixpt_one;
int n = 26;
do {
res = spl_fixpt_sub(
spl_fixpt_one,
spl_fixpt_div_int(
SPL_NAMESPACE(spl_fixpt_mul(
square,
res)),
n * (n - 1)));
n -= 2;
} while (n != 0);
return res;
}
/*
* @brief
* result = exp(arg),
* where abs(arg) < 1
*
* Calculated as Taylor series.
*/
static struct spl_fixed31_32 spl_fixed31_32_exp_from_taylor_series(struct spl_fixed31_32 arg)
{
unsigned int n = 9;
struct spl_fixed31_32 res = SPL_NAMESPACE(spl_fixpt_from_fraction(
n + 2,
n + 1));
/* TODO find correct res */
SPL_ASSERT(spl_fixpt_lt(arg, spl_fixpt_one));
do
res = spl_fixpt_add(
spl_fixpt_one,
spl_fixpt_div_int(
SPL_NAMESPACE(spl_fixpt_mul(
arg,
res)),
n));
while (--n != 1);
return spl_fixpt_add(
spl_fixpt_one,
SPL_NAMESPACE(spl_fixpt_mul(
arg,
res)));
}
struct spl_fixed31_32 SPL_NAMESPACE(spl_fixpt_exp(struct spl_fixed31_32 arg))
{
/*
* @brief
* Main equation is:
* exp(x) = exp(r + m * ln(2)) = (1 << m) * exp(r),
* where m = round(x / ln(2)), r = x - m * ln(2)
*/
if (spl_fixpt_le(
spl_fixpt_ln2_div_2,
spl_fixpt_abs(arg))) {
int m = spl_fixpt_round(
spl_fixpt_div(
arg,
spl_fixpt_ln2));
struct spl_fixed31_32 r = spl_fixpt_sub(
arg,
spl_fixpt_mul_int(
spl_fixpt_ln2,
m));
SPL_ASSERT(m != 0);
SPL_ASSERT(spl_fixpt_lt(
spl_fixpt_abs(r),
spl_fixpt_one));
if (m > 0)
return spl_fixpt_shl(
spl_fixed31_32_exp_from_taylor_series(r),
(unsigned int)m);
else
return spl_fixpt_div_int(
spl_fixed31_32_exp_from_taylor_series(r),
1LL << -m);
} else if (arg.value != 0)
return spl_fixed31_32_exp_from_taylor_series(arg);
else
return spl_fixpt_one;
}
struct spl_fixed31_32 SPL_NAMESPACE(spl_fixpt_log(struct spl_fixed31_32 arg))
{
struct spl_fixed31_32 res = spl_fixpt_neg(spl_fixpt_one);
/* TODO improve 1st estimation */
struct spl_fixed31_32 error;
SPL_ASSERT(arg.value > 0);
/* TODO if arg is negative, return NaN */
/* TODO if arg is zero, return -INF */
do {
struct spl_fixed31_32 res1 = spl_fixpt_add(
spl_fixpt_sub(
res,
spl_fixpt_one),
spl_fixpt_div(
arg,
SPL_NAMESPACE(spl_fixpt_exp(res))));
error = spl_fixpt_sub(
res,
res1);
res = res1;
/* TODO determine max_allowed_error based on quality of exp() */
} while (abs_i64(error.value) > 100ULL);
return res;
}
/* this function is a generic helper to translate fixed point value to
* specified integer format that will consist of integer_bits integer part and
* fractional_bits fractional part. For example it is used in
* spl_fixpt_u2d19 to receive 2 bits integer part and 19 bits fractional
* part in 32 bits. It is used in hw programming (scaler)
*/
static inline unsigned int spl_ux_dy(
long long value,
unsigned int integer_bits,
unsigned int fractional_bits)
{
/* 1. create mask of integer part */
unsigned int result = (1 << integer_bits) - 1;
/* 2. mask out fractional part */
unsigned int fractional_part = FRACTIONAL_PART_MASK & value;
/* 3. shrink fixed point integer part to be of integer_bits width*/
result &= GET_INTEGER_PART(value);
/* 4. make space for fractional part to be filled in after integer */
result <<= fractional_bits;
/* 5. shrink fixed point fractional part to of fractional_bits width*/
fractional_part >>= FIXED31_32_BITS_PER_FRACTIONAL_PART - fractional_bits;
/* 6. merge the result */
return result | fractional_part;
}
static inline unsigned int spl_clamp_ux_dy(
long long value,
unsigned int integer_bits,
unsigned int fractional_bits,
unsigned int min_clamp)
{
unsigned int truncated_val = spl_ux_dy(value, integer_bits, fractional_bits);
if (value >= (1LL << (integer_bits + FIXED31_32_BITS_PER_FRACTIONAL_PART)))
return (1 << (integer_bits + fractional_bits)) - 1;
else if (truncated_val > min_clamp)
return truncated_val;
else
return min_clamp;
}
unsigned int SPL_NAMESPACE(spl_fixpt_u4d19(struct spl_fixed31_32 arg))
{
return spl_ux_dy(arg.value, 4, 19);
}
unsigned int SPL_NAMESPACE(spl_fixpt_u3d19(struct spl_fixed31_32 arg))
{
return spl_ux_dy(arg.value, 3, 19);
}
unsigned int SPL_NAMESPACE(spl_fixpt_u2d19(struct spl_fixed31_32 arg))
{
return spl_ux_dy(arg.value, 2, 19);
}
unsigned int SPL_NAMESPACE(spl_fixpt_u0d19(struct spl_fixed31_32 arg))
{
return spl_ux_dy(arg.value, 0, 19);
}
unsigned int SPL_NAMESPACE(spl_fixpt_clamp_u0d14(struct spl_fixed31_32 arg))
{
return spl_clamp_ux_dy(arg.value, 0, 14, 1);
}
unsigned int SPL_NAMESPACE(spl_fixpt_clamp_u0d10(struct spl_fixed31_32 arg))
{
return spl_clamp_ux_dy(arg.value, 0, 10, 1);
}
int SPL_NAMESPACE(spl_fixpt_s4d19(struct spl_fixed31_32 arg))
{
if (arg.value < 0)
return -(int)spl_ux_dy(spl_fixpt_abs(arg).value, 4, 19);
else
return spl_ux_dy(arg.value, 4, 19);
}
struct spl_fixed31_32 SPL_NAMESPACE(spl_fixpt_from_ux_dy(unsigned int value,
unsigned int integer_bits,
unsigned int fractional_bits))
{
struct spl_fixed31_32 fixpt_value = spl_fixpt_zero;
struct spl_fixed31_32 fixpt_int_value = spl_fixpt_zero;
long long frac_mask = ((long long)1 << (long long)integer_bits) - 1;
fixpt_value.value = (long long)value << (FIXED31_32_BITS_PER_FRACTIONAL_PART - fractional_bits);
frac_mask = frac_mask << fractional_bits;
fixpt_int_value.value = value & frac_mask;
fixpt_int_value.value <<= (FIXED31_32_BITS_PER_FRACTIONAL_PART - fractional_bits);
fixpt_value.value |= fixpt_int_value.value;
return fixpt_value;
}
struct spl_fixed31_32 SPL_NAMESPACE(spl_fixpt_from_int_dy(unsigned int int_value,
unsigned int frac_value,
unsigned int integer_bits,
unsigned int fractional_bits))
{
struct spl_fixed31_32 fixpt_value = spl_fixpt_from_int(int_value);
fixpt_value.value |= (long long)frac_value << (FIXED31_32_BITS_PER_FRACTIONAL_PART - fractional_bits);
return fixpt_value;
}
@@ -0,0 +1,526 @@
/* SPDX-License-Identifier: MIT */
/* Copyright 2024 Advanced Micro Devices, Inc. */
#ifndef __SPL_FIXED31_32_H__
#define __SPL_FIXED31_32_H__
#include "spl_debug.h"
#include "spl_os_types.h" // swap
#ifndef LLONG_MAX
#define LLONG_MAX 9223372036854775807ll
#endif
#ifndef LLONG_MIN
#define LLONG_MIN (-LLONG_MAX - 1ll)
#endif
#define FIXED31_32_BITS_PER_FRACTIONAL_PART 32
#ifndef LLONG_MIN
#define LLONG_MIN (1LL<<63)
#endif
#ifndef LLONG_MAX
#define LLONG_MAX (-1LL>>1)
#endif
/*
* @brief
* Arithmetic operations on real numbers
* represented as fixed-point numbers.
* There are: 1 bit for sign,
* 31 bit for integer part,
* 32 bits for fractional part.
*
* @note
* Currently, overflows and underflows are asserted;
* no special result returned.
*/
struct spl_fixed31_32 {
long long value;
};
/*
* @brief
* Useful constants
*/
static const struct spl_fixed31_32 spl_fixpt_zero = { 0 };
static const struct spl_fixed31_32 spl_fixpt_epsilon = { 1LL };
static const struct spl_fixed31_32 spl_fixpt_half = { 0x80000000LL };
static const struct spl_fixed31_32 spl_fixpt_one = { 0x100000000LL };
/*
* @brief
* Initialization routines
*/
/*
* @brief
* result = numerator / denominator
*/
struct spl_fixed31_32 SPL_NAMESPACE(spl_fixpt_from_fraction(
long long numerator, long long denominator));
/*
* @brief
* result = arg
*/
static inline struct spl_fixed31_32 spl_fixpt_from_int(int arg)
{
struct spl_fixed31_32 res;
res.value = (long long) arg << FIXED31_32_BITS_PER_FRACTIONAL_PART;
return res;
}
/*
* @brief
* Unary operators
*/
/*
* @brief
* result = -arg
*/
static inline struct spl_fixed31_32 spl_fixpt_neg(struct spl_fixed31_32 arg)
{
struct spl_fixed31_32 res;
res.value = -arg.value;
return res;
}
/*
* @brief
* result = abs(arg) := (arg >= 0) ? arg : -arg
*/
static inline struct spl_fixed31_32 spl_fixpt_abs(struct spl_fixed31_32 arg)
{
if (arg.value < 0)
return spl_fixpt_neg(arg);
else
return arg;
}
/*
* @brief
* Binary relational operators
*/
/*
* @brief
* result = arg1 < arg2
*/
static inline bool spl_fixpt_lt(struct spl_fixed31_32 arg1, struct spl_fixed31_32 arg2)
{
return arg1.value < arg2.value;
}
/*
* @brief
* result = arg1 <= arg2
*/
static inline bool spl_fixpt_le(struct spl_fixed31_32 arg1, struct spl_fixed31_32 arg2)
{
return arg1.value <= arg2.value;
}
/*
* @brief
* result = arg1 == arg2
*/
static inline bool spl_fixpt_eq(struct spl_fixed31_32 arg1, struct spl_fixed31_32 arg2)
{
return arg1.value == arg2.value;
}
/*
* @brief
* result = min(arg1, arg2) := (arg1 <= arg2) ? arg1 : arg2
*/
static inline struct spl_fixed31_32 spl_fixpt_min(struct spl_fixed31_32 arg1, struct spl_fixed31_32 arg2)
{
if (arg1.value <= arg2.value)
return arg1;
else
return arg2;
}
/*
* @brief
* result = max(arg1, arg2) := (arg1 <= arg2) ? arg2 : arg1
*/
static inline struct spl_fixed31_32 spl_fixpt_max(struct spl_fixed31_32 arg1, struct spl_fixed31_32 arg2)
{
if (arg1.value <= arg2.value)
return arg2;
else
return arg1;
}
/*
* @brief
* | min_value, when arg <= min_value
* result = | arg, when min_value < arg < max_value
* | max_value, when arg >= max_value
*/
static inline struct spl_fixed31_32 spl_fixpt_clamp(
struct spl_fixed31_32 arg,
struct spl_fixed31_32 min_value,
struct spl_fixed31_32 max_value)
{
if (spl_fixpt_le(arg, min_value))
return min_value;
else if (spl_fixpt_le(max_value, arg))
return max_value;
else
return arg;
}
/*
* @brief
* Binary shift operators
*/
/*
* @brief
* result = arg << shift
*/
static inline struct spl_fixed31_32 spl_fixpt_shl(struct spl_fixed31_32 arg, unsigned int shift)
{
SPL_ASSERT(((arg.value >= 0) && (arg.value <= LLONG_MAX >> shift)) ||
((arg.value < 0) && (arg.value >= ~(LLONG_MAX >> shift))));
arg.value = arg.value << shift;
return arg;
}
/*
* @brief
* result = arg >> shift
*/
static inline struct spl_fixed31_32 spl_fixpt_shr(struct spl_fixed31_32 arg, unsigned int shift)
{
bool negative = arg.value < 0;
if (negative)
arg.value = -arg.value;
arg.value = arg.value >> shift;
if (negative)
arg.value = -arg.value;
return arg;
}
/*
* @brief
* Binary additive operators
*/
/*
* @brief
* result = arg1 + arg2
*/
static inline struct spl_fixed31_32 spl_fixpt_add(struct spl_fixed31_32 arg1, struct spl_fixed31_32 arg2)
{
struct spl_fixed31_32 res;
SPL_ASSERT(((arg1.value >= 0) && (LLONG_MAX - arg1.value >= arg2.value)) ||
((arg1.value < 0) && (LLONG_MIN - arg1.value <= arg2.value)));
res.value = arg1.value + arg2.value;
return res;
}
/*
* @brief
* result = arg1 + arg2
*/
static inline struct spl_fixed31_32 spl_fixpt_add_int(struct spl_fixed31_32 arg1, int arg2)
{
return spl_fixpt_add(arg1, spl_fixpt_from_int(arg2));
}
/*
* @brief
* result = arg1 - arg2
*/
static inline struct spl_fixed31_32 spl_fixpt_sub(struct spl_fixed31_32 arg1, struct spl_fixed31_32 arg2)
{
struct spl_fixed31_32 res;
SPL_ASSERT(((arg2.value >= 0) && (LLONG_MIN + arg2.value <= arg1.value)) ||
((arg2.value < 0) && (LLONG_MAX + arg2.value >= arg1.value)));
res.value = arg1.value - arg2.value;
return res;
}
/*
* @brief
* result = arg1 - arg2
*/
static inline struct spl_fixed31_32 spl_fixpt_sub_int(struct spl_fixed31_32 arg1, int arg2)
{
return spl_fixpt_sub(arg1, spl_fixpt_from_int(arg2));
}
/*
* @brief
* Binary multiplicative operators
*/
/*
* @brief
* result = arg1 * arg2
*/
struct spl_fixed31_32 SPL_NAMESPACE(spl_fixpt_mul(
struct spl_fixed31_32 arg1, struct spl_fixed31_32 arg2));
/*
* @brief
* result = arg1 * arg2
*/
static inline struct spl_fixed31_32 spl_fixpt_mul_int(struct spl_fixed31_32 arg1, int arg2)
{
return SPL_NAMESPACE(spl_fixpt_mul(arg1, spl_fixpt_from_int(arg2)));
}
/*
* @brief
* result = square(arg) := arg * arg
*/
struct spl_fixed31_32 SPL_NAMESPACE(spl_fixpt_sqr(struct spl_fixed31_32 arg));
/*
* @brief
* result = arg1 / arg2
*/
static inline struct spl_fixed31_32 spl_fixpt_div_int(struct spl_fixed31_32 arg1, long long arg2)
{
return SPL_NAMESPACE(spl_fixpt_from_fraction(arg1.value,
spl_fixpt_from_int((int)arg2).value));
}
/*
* @brief
* result = arg1 / arg2
*/
static inline struct spl_fixed31_32 spl_fixpt_div(struct spl_fixed31_32 arg1, struct spl_fixed31_32 arg2)
{
return SPL_NAMESPACE(spl_fixpt_from_fraction(arg1.value, arg2.value));
}
/*
* @brief
* Reciprocal function
*/
/*
* @brief
* result = reciprocal(arg) := 1 / arg
*
* @note
* No special actions taken in case argument is zero.
*/
struct spl_fixed31_32 SPL_NAMESPACE(spl_fixpt_recip(struct spl_fixed31_32 arg));
/*
* @brief
* Trigonometric functions
*/
/*
* @brief
* result = sinc(arg) := sin(arg) / arg
*
* @note
* Argument specified in radians,
* internally it's normalized to [-2pi...2pi] range.
*/
struct spl_fixed31_32 SPL_NAMESPACE(spl_fixpt_sinc(struct spl_fixed31_32 arg));
/*
* @brief
* result = sin(arg)
*
* @note
* Argument specified in radians,
* internally it's normalized to [-2pi...2pi] range.
*/
struct spl_fixed31_32 SPL_NAMESPACE(spl_fixpt_sin(struct spl_fixed31_32 arg));
/*
* @brief
* result = cos(arg)
*
* @note
* Argument specified in radians
* and should be in [-2pi...2pi] range -
* passing arguments outside that range
* will cause incorrect result!
*/
struct spl_fixed31_32 SPL_NAMESPACE(spl_fixpt_cos(struct spl_fixed31_32 arg));
/*
* @brief
* Transcendent functions
*/
/*
* @brief
* result = exp(arg)
*
* @note
* Currently, function is verified for abs(arg) <= 1.
*/
struct spl_fixed31_32 SPL_NAMESPACE(spl_fixpt_exp(struct spl_fixed31_32 arg));
/*
* @brief
* result = log(arg)
*
* @note
* Currently, abs(arg) should be less than 1.
* No normalization is done.
* Currently, no special actions taken
* in case of invalid argument(s). Take care!
*/
struct spl_fixed31_32 SPL_NAMESPACE(spl_fixpt_log(struct spl_fixed31_32 arg));
/*
* @brief
* Power function
*/
/*
* @brief
* result = pow(arg1, arg2)
*
* @note
* Currently, abs(arg1) should be less than 1. Take care!
*/
static inline struct spl_fixed31_32 spl_fixpt_pow(struct spl_fixed31_32 arg1, struct spl_fixed31_32 arg2)
{
if (arg1.value == 0)
return arg2.value == 0 ? spl_fixpt_one : spl_fixpt_zero;
return SPL_NAMESPACE(spl_fixpt_exp(
SPL_NAMESPACE(spl_fixpt_mul(
SPL_NAMESPACE(spl_fixpt_log(arg1)),
arg2))));
}
/*
* @brief
* Rounding functions
*/
/*
* @brief
* result = floor(arg) := greatest integer lower than or equal to arg
*/
static inline int spl_fixpt_floor(struct spl_fixed31_32 arg)
{
unsigned long long arg_value = arg.value > 0 ? arg.value : -arg.value;
if (arg.value >= 0)
return (int)(arg_value >> FIXED31_32_BITS_PER_FRACTIONAL_PART);
else
return -(int)(arg_value >> FIXED31_32_BITS_PER_FRACTIONAL_PART);
}
/*
* @brief
* result = round(arg) := integer nearest to arg
*/
static inline int spl_fixpt_round(struct spl_fixed31_32 arg)
{
unsigned long long arg_value = arg.value > 0 ? arg.value : -arg.value;
const long long summand = spl_fixpt_half.value;
SPL_ASSERT(LLONG_MAX - (long long)arg_value >= summand);
arg_value += summand;
if (arg.value >= 0)
return (int)(arg_value >> FIXED31_32_BITS_PER_FRACTIONAL_PART);
else
return -(int)(arg_value >> FIXED31_32_BITS_PER_FRACTIONAL_PART);
}
/*
* @brief
* result = ceil(arg) := lowest integer greater than or equal to arg
*/
static inline int spl_fixpt_ceil(struct spl_fixed31_32 arg)
{
unsigned long long arg_value = arg.value > 0 ? arg.value : -arg.value;
const long long summand = spl_fixpt_one.value -
spl_fixpt_epsilon.value;
SPL_ASSERT(LLONG_MAX - (long long)arg_value >= summand);
arg_value += summand;
if (arg.value >= 0)
return (int)(arg_value >> FIXED31_32_BITS_PER_FRACTIONAL_PART);
else
return -(int)(arg_value >> FIXED31_32_BITS_PER_FRACTIONAL_PART);
}
/* the following two function are used in scaler hw programming to convert fixed
* point value to format 2 bits from integer part and 19 bits from fractional
* part. The same applies for u0d19, 0 bits from integer part and 19 bits from
* fractional
*/
unsigned int SPL_NAMESPACE(spl_fixpt_u4d19(struct spl_fixed31_32 arg));
unsigned int SPL_NAMESPACE(spl_fixpt_u3d19(struct spl_fixed31_32 arg));
unsigned int SPL_NAMESPACE(spl_fixpt_u2d19(struct spl_fixed31_32 arg));
unsigned int SPL_NAMESPACE(spl_fixpt_u0d19(struct spl_fixed31_32 arg));
unsigned int SPL_NAMESPACE(spl_fixpt_clamp_u0d14(struct spl_fixed31_32 arg));
unsigned int SPL_NAMESPACE(spl_fixpt_clamp_u0d10(struct spl_fixed31_32 arg));
int SPL_NAMESPACE(spl_fixpt_s4d19(struct spl_fixed31_32 arg));
static inline struct spl_fixed31_32 spl_fixpt_truncate(struct spl_fixed31_32 arg, unsigned int frac_bits)
{
bool negative = arg.value < 0;
if (frac_bits >= FIXED31_32_BITS_PER_FRACTIONAL_PART) {
SPL_ASSERT(frac_bits == FIXED31_32_BITS_PER_FRACTIONAL_PART);
return arg;
}
if (negative)
arg.value = -arg.value;
arg.value &= (~0ULL) << (FIXED31_32_BITS_PER_FRACTIONAL_PART - frac_bits);
if (negative)
arg.value = -arg.value;
return arg;
}
struct spl_fixed31_32 SPL_NAMESPACE(spl_fixpt_from_ux_dy(unsigned int value,
unsigned int integer_bits, unsigned int fractional_bits));
struct spl_fixed31_32 SPL_NAMESPACE(spl_fixpt_from_int_dy(unsigned int int_value,
unsigned int frac_value,
unsigned int integer_bits,
unsigned int fractional_bits));
#endif
@@ -0,0 +1,65 @@
/* SPDX-License-Identifier: MIT */
/* Copyright 2024 Advanced Micro Devices, Inc. */
/* Copyright 2019 Raptor Engineering, LLC */
#ifndef _SPL_OS_TYPES_H_
#define _SPL_OS_TYPES_H_
#include "spl_debug.h"
#include <linux/slab.h>
#include <linux/kgdb.h>
#include <linux/kref.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/mm.h>
/*
*
* general debug capabilities
*
*/
static inline uint64_t spl_div_u64_rem(uint64_t dividend, uint32_t divisor, uint32_t *remainder)
{
return div_u64_rem(dividend, divisor, remainder);
}
static inline uint64_t spl_div_u64(uint64_t dividend, uint32_t divisor)
{
return div_u64(dividend, divisor);
}
static inline uint64_t spl_div64_u64(uint64_t dividend, uint64_t divisor)
{
return div64_u64(dividend, divisor);
}
static inline uint64_t spl_div64_u64_rem(uint64_t dividend, uint64_t divisor, uint64_t *remainder)
{
return div64_u64_rem(dividend, divisor, remainder);
}
static inline int64_t spl_div64_s64(int64_t dividend, int64_t divisor)
{
return div64_s64(dividend, divisor);
}
#define spl_swap(a, b) \
do { typeof(a) __tmp = (a); (a) = (b); (b) = __tmp; } while (0)
#ifndef spl_min
#define spl_min(a, b) (((a) < (b)) ? (a):(b))
#endif
/* SPL namespace macros */
#ifndef SPL_PFX_
#define SPL_PFX_
#endif
#define SPL_EXPAND2(a, b) a##b
#define SPL_EXPAND(a, b) SPL_EXPAND2(a, b)
#define SPL_NAMESPACE(symbol) SPL_EXPAND(SPL_PFX_, symbol)
#endif /* _SPL_OS_TYPES_H_ */