video: HDR display/output support (BT2020 / DCI P3) (#718)
* Merge branch 'hdr' of https://github.com/wickerwaka/Main_MiSTer into feature-hdr Merged in wickerwaka's old HDR branch and integrated the BT2020 and DCI P3 color space conversion matrices. Changed "hdr" option to be a selection of matrix instead of saturation option. * Add HDR example to MiSTer ini
This commit is contained in:
@@ -20,6 +20,9 @@ menu_pal=0 ; 1 - PAL mode for menu core
|
||||
hdmi_limited=0 ; 1 - use limited (16..235) color range over HDMI
|
||||
; 2 - use limited (16..255) color range over HDMI, for VGA converters.
|
||||
direct_video=0 ; 1 - enable core video timing over HDMI, use only with VGA converters.
|
||||
hdr=0 ; 1 - enable HDR using the BT2020 color space (faux-HDR, use color controls to tweak).
|
||||
; 2 - enable HDR using the DCI P3 color space.
|
||||
; 3 - enable HDR without color space conversion.
|
||||
fb_size=0 ; 0 - automatic, 1 - full size, 2 - 1/2 of resolution, 4 - 1/4 of resolution.
|
||||
fb_terminal=1 ; 1 - enabled (default), 0 - disabled
|
||||
osd_timeout=30 ; 5-3600 timeout (in seconds) for OSD to disappear in Menu core. 0 - never timeout.
|
||||
|
||||
2
cfg.cpp
2
cfg.cpp
@@ -113,6 +113,7 @@ static const ini_var_t ini_vars[] =
|
||||
{ "VIDEO_SATURATION", (void *)(&(cfg.video_saturation)), UINT16, 0, 100},
|
||||
{ "VIDEO_HUE", (void *)(&(cfg.video_hue)), UINT16, 0, 360},
|
||||
{ "VIDEO_GAIN_OFFSET", (void *)(&(cfg.video_gain_offset)), STRING, 0, sizeof(cfg.video_gain_offset)},
|
||||
{ "HDR", (void*)(&cfg.hdr), UINT8, 0, 3 },
|
||||
};
|
||||
|
||||
static const int nvars = (int)(sizeof(ini_vars) / sizeof(ini_var_t));
|
||||
@@ -445,6 +446,7 @@ void cfg_parse()
|
||||
cfg.rumble = 1;
|
||||
cfg.wheel_force = 50;
|
||||
cfg.dvi_mode = 2;
|
||||
cfg.hdr = 0;
|
||||
cfg.video_brightness = 50;
|
||||
cfg.video_contrast = 50;
|
||||
cfg.video_saturation = 100;
|
||||
|
||||
1
cfg.h
1
cfg.h
@@ -85,6 +85,7 @@ typedef struct {
|
||||
uint16_t video_saturation;
|
||||
uint16_t video_hue;
|
||||
char video_gain_offset[256];
|
||||
uint8_t hdr;
|
||||
} cfg_t;
|
||||
|
||||
extern cfg_t cfg;
|
||||
|
||||
0
setup_default_toolchain.sh
Executable file → Normal file
0
setup_default_toolchain.sh
Executable file → Normal file
0
str_util.cpp
Executable file → Normal file
0
str_util.cpp
Executable file → Normal file
0
str_util.h
Executable file → Normal file
0
str_util.h
Executable file → Normal file
105
video.cpp
105
video.cpp
@@ -1044,16 +1044,17 @@ static void hdmi_config_set_spd(bool val)
|
||||
}
|
||||
}
|
||||
|
||||
static void hdmi_config_set_spare(bool val)
|
||||
static void hdmi_config_set_spare(int packet, bool enabled)
|
||||
{
|
||||
int fd = i2c_open(0x39, 0);
|
||||
uint8_t mask = packet == 0 ? 0x01 : 0x02;
|
||||
if (fd >= 0)
|
||||
{
|
||||
uint8_t packet_val = i2c_smbus_read_byte_data(fd, 0x40);
|
||||
if (val)
|
||||
packet_val |= 0x01;
|
||||
if (enabled)
|
||||
packet_val |= mask;
|
||||
else
|
||||
packet_val &= ~0x01;
|
||||
packet_val &= ~mask;
|
||||
int res = i2c_smbus_write_byte_data(fd, 0x40, packet_val);
|
||||
if (res < 0) printf("i2c: write error (%02X %02X): %d\n", 0x40, packet_val, res);
|
||||
i2c_close(fd);
|
||||
@@ -1094,16 +1095,35 @@ static void hdmi_config_set_csc()
|
||||
0.0f, 0.0f, 0.0f, 1.0f
|
||||
};
|
||||
|
||||
float hdr_bt2020_coeffs[] = {
|
||||
0.6274f, 0.3293f, 0.0433f, 0.0f,
|
||||
0.0691f, 0.9195f, 0.0114f, 0.0f,
|
||||
0.0164f, 0.0880f, 0.8956f, 0.0f,
|
||||
0.0f, 0.0f, 0.0f, 1.0f
|
||||
};
|
||||
|
||||
float hdr_dcip3_coeffs[] = {
|
||||
0.8225f, 0.1774f, 0.0000f, 0.0f,
|
||||
0.0332f, 0.9669f, 0.0000f, 0.0f,
|
||||
0.0171f, 0.0724f, 0.9108f, 0.0f,
|
||||
0.0f, 0.0f, 0.0f, 1.0f
|
||||
};
|
||||
|
||||
const float pi = float(M_PI);
|
||||
|
||||
// select the base CSC
|
||||
int ypbpr = cfg.ypbpr && cfg.direct_video;
|
||||
int hdmi_limited_1 = cfg.hdmi_limited & 1;
|
||||
int hdmi_limited_2 = cfg.hdmi_limited & 2;
|
||||
int hdr = cfg.hdr;
|
||||
|
||||
mat4x4 coeffs = hdmi_full_coeffs;
|
||||
|
||||
if (ypbpr)
|
||||
if (hdr == 1)
|
||||
coeffs = hdr_bt2020_coeffs;
|
||||
else if (hdr == 2)
|
||||
coeffs = hdr_dcip3_coeffs;
|
||||
else if (ypbpr)
|
||||
coeffs = ypbpr_coeffs;
|
||||
else if (hdmi_limited_1)
|
||||
coeffs = hdmi_limited_1_coeffs;
|
||||
@@ -1358,12 +1378,12 @@ static void hdmi_config_init()
|
||||
// Bar Info [3:2] b00 Bars invalid. b01 Bars vertical. b10 Bars horizontal. b11 Bars both.
|
||||
// Scan Info [1:0] b00 (No data). b01 TV. b10 PC. b11 None.
|
||||
|
||||
0x56, 0b00001000, // [5:4] Picture Aspect Ratio
|
||||
0x56, (uint8_t)( 0b00001000 | (cfg.hdr ? 0xb11000000 : 0)), // [5:4] Picture Aspect Ratio
|
||||
// [3:0] Active Portion Aspect Ratio b1000 = Same as Picture Aspect Ratio
|
||||
|
||||
0x57, (uint8_t)((cfg.hdmi_game_mode ? 0x80 : 0x00) // [7] IT Content. 0 - No. 1 - Yes (type set in register 0x59).
|
||||
// [6:4] Color space (ignored for RGB)
|
||||
| ((ypbpr || cfg.hdmi_limited) ? 0b0100 : 0b1000)), // [3:2] RGB Quantization range
|
||||
| ((ypbpr || cfg.hdmi_limited) ? 0b0100 : cfg.hdr ? 0b1101000 : 0b0001000)), // [3:2] RGB Quantization range
|
||||
// [1:0] Non-Uniform Scaled: 00 - None. 01 - Horiz. 10 - Vert. 11 - Both.
|
||||
|
||||
0x59, (uint8_t)(cfg.hdmi_game_mode ? 0x30 : 0x00), // [7:6] [YQ1 YQ0] YCC Quantization Range: b00 = Limited Range, b01 = Full Range
|
||||
@@ -1459,6 +1479,68 @@ static void hdmi_config_init()
|
||||
hdmi_config_set_csc();
|
||||
}
|
||||
|
||||
static void hdmi_config_set_hdr()
|
||||
{
|
||||
// 87:01:1a:74:02:00:c2:33:c4:86:4c:1d:b8:0b:d0:84:80 :3e:13:3d:42:40:e8:03:32:00:e8:03:90:01
|
||||
uint8_t hdr_data[] = {
|
||||
0x87,
|
||||
0x01,
|
||||
0x1a,
|
||||
0x74,
|
||||
0x02,
|
||||
0x00,
|
||||
0xc2,
|
||||
0x33,
|
||||
0xc4,
|
||||
0x86,
|
||||
0x4c,
|
||||
0x1d,
|
||||
0xb8,
|
||||
0x0b,
|
||||
0xd0,
|
||||
0x84,
|
||||
0x80,
|
||||
0x3e,
|
||||
0x13,
|
||||
0x3d,
|
||||
0x42,
|
||||
0x40,
|
||||
0xe8,
|
||||
0x03,
|
||||
0x32,
|
||||
0x00,
|
||||
0xe8,
|
||||
0x03,
|
||||
0x90,
|
||||
0x01
|
||||
};
|
||||
|
||||
if (cfg.hdr == 0)
|
||||
{
|
||||
hdmi_config_set_spare(1, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
hdmi_config_set_spare(1, true);
|
||||
int fd = i2c_open(0x38, 0);
|
||||
int res = i2c_smbus_write_byte_data(fd, 0xFF, 0b10000000);
|
||||
if (res < 0)
|
||||
{
|
||||
printf("i2c: hdr: Couldn't update Spare Packet change register (0xDF, 0x80) %d\n", res);
|
||||
}
|
||||
|
||||
uint8_t addr = 0xe0;
|
||||
for (uint i = 0; i < sizeof(hdr_data); i++)
|
||||
{
|
||||
res = i2c_smbus_write_byte_data(fd, addr, hdr_data[i]);
|
||||
if (res < 0) printf("i2c: hdr register write error (%02X %02x): %d\n", addr, hdr_data[i], res);
|
||||
addr += 1;
|
||||
}
|
||||
res = i2c_smbus_write_byte_data(fd, 0xfF, 0x00);
|
||||
if (res < 0) printf("i2c: hdr: Couldn't update Spare Packet change register (0xDF, 0x00), %d\n", res);
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t last_sync_invert = 0xff;
|
||||
static uint8_t last_pr_flags = 0xff;
|
||||
static uint8_t last_vic_mode = 0xff;
|
||||
@@ -1786,8 +1868,8 @@ static void set_vrr_mode()
|
||||
{
|
||||
if (last_vrr_mode != 0)
|
||||
{
|
||||
hdmi_config_set_spd(0);
|
||||
hdmi_config_set_spare(0);
|
||||
hdmi_config_set_spd(false);
|
||||
hdmi_config_set_spare(0, false);
|
||||
}
|
||||
last_vrr_mode = 0;
|
||||
return;
|
||||
@@ -1924,7 +2006,7 @@ static void set_vrr_mode()
|
||||
|
||||
if (use_vrr == VRR_VESA)
|
||||
{
|
||||
hdmi_config_set_spare(1);
|
||||
hdmi_config_set_spare(0, true);
|
||||
res = i2c_smbus_write_byte_data(fd, 0xDF, 0b10000000);
|
||||
if (res < 0)
|
||||
{
|
||||
@@ -1941,7 +2023,7 @@ static void set_vrr_mode()
|
||||
}
|
||||
else
|
||||
{
|
||||
hdmi_config_set_spare(0);
|
||||
hdmi_config_set_spare(0, false);
|
||||
}
|
||||
i2c_close(fd);
|
||||
}
|
||||
@@ -2222,6 +2304,7 @@ void video_init()
|
||||
{
|
||||
fb_init();
|
||||
hdmi_config_init();
|
||||
hdmi_config_set_hdr();
|
||||
video_mode_load();
|
||||
|
||||
has_gamma = spi_uio_cmd(UIO_SET_GAMMA);
|
||||
|
||||
Reference in New Issue
Block a user