diff --git a/MiSTer.ini b/MiSTer.ini index 035dbdc..95b951f 100644 --- a/MiSTer.ini +++ b/MiSTer.ini @@ -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. diff --git a/cfg.cpp b/cfg.cpp index 42eb650..8d8ddfa 100644 --- a/cfg.cpp +++ b/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; diff --git a/cfg.h b/cfg.h index e6cd7e5..3751af8 100644 --- a/cfg.h +++ b/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; diff --git a/mat4x4.h b/mat4x4.h old mode 100755 new mode 100644 diff --git a/setup_default_toolchain.sh b/setup_default_toolchain.sh old mode 100755 new mode 100644 diff --git a/str_util.cpp b/str_util.cpp old mode 100755 new mode 100644 diff --git a/str_util.h b/str_util.h old mode 100755 new mode 100644 diff --git a/video.cpp b/video.cpp index 8623a27..90cd3d9 100644 --- a/video.cpp +++ b/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);