diff --git a/MiSTer.ini b/MiSTer.ini index 608246e..725d48e 100644 --- a/MiSTer.ini +++ b/MiSTer.ini @@ -137,6 +137,17 @@ video_saturation=100 video_hue=0 video_gain_offset=1,0,1,0,1,0 +; These controls have been provided so you can tweak the HDR metadata values regarding +; peak brightness and average brightness. The defaults are 1000/250 for peak and average +; respectively. +; Some displays will completely ignore the values in the HDR packet, some will make use of them. +; The recommendation is to set hdr_max_nits to your display's peak luminance, while +; setting hdr_avg_nits to at least hdr_max_nits/4. +; Please note that setting a peak brightness far above your display's capability may result +; in clipping in bright parts of the image. +hdr_max_nits=1000 +hdr_avg_nits=250 + ; 1-10 (seconds) to display controller's button map upon first time key press ; 0 - disable controller_info=6 diff --git a/cfg.cpp b/cfg.cpp index dc09c14..b2cc48a 100644 --- a/cfg.cpp +++ b/cfg.cpp @@ -115,6 +115,8 @@ static const ini_var_t ini_vars[] = { "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, 2 }, + { "HDR_MAX_NITS", (void*)(&(cfg.hdr_max_nits)), UINT16, 100, 10000}, + { "HDR_AVG_NITS", (void*)(&(cfg.hdr_avg_nits)), UINT16, 100, 10000}, { "VGA_MODE", (void*)(&(cfg.vga_mode)), STRING, 0, sizeof(cfg.vga_mode) - 1 }, { "NTSC_MODE", (void *)(&(cfg.ntsc_mode)), UINT8, 0, 2}, }; @@ -450,6 +452,8 @@ void cfg_parse() cfg.wheel_force = 50; cfg.dvi_mode = 2; cfg.hdr = 0; + cfg.hdr_max_nits = 1000; + cfg.hdr_avg_nits = 250; cfg.video_brightness = 50; cfg.video_contrast = 50; cfg.video_saturation = 100; diff --git a/cfg.h b/cfg.h index 8a86c1f..33f7030 100644 --- a/cfg.h +++ b/cfg.h @@ -86,6 +86,8 @@ typedef struct { uint16_t video_hue; char video_gain_offset[256]; uint8_t hdr; + uint16_t hdr_max_nits; + uint16_t hdr_avg_nits; char vga_mode[16]; char vga_mode_int; char ntsc_mode; diff --git a/video.cpp b/video.cpp index 2be7d1f..dafddfb 100644 --- a/video.cpp +++ b/video.cpp @@ -1174,25 +1174,10 @@ static void hdmi_config_set_csc() if (!ypbpr) { - // select the base CSC int hdr = cfg.hdr; - mat4x4 coeffs = hdmi_full_coeffs; - - if (hdr == 1) - coeffs = hdmi_full_coeffs; - else if (hdr == 2) - coeffs = hdr_dcip3_coeffs; - else - { - if (hdmi_limited_1) - coeffs = hdmi_limited_1_coeffs; - else if (hdmi_limited_2) - coeffs = hdmi_limited_2_coeffs; - else - coeffs = hdmi_full_coeffs; - } + mat4x4 coeffs = hdr == 2 ? hdr_dcip3_coeffs : hdmi_full_coeffs; mat4x4 csc(coeffs); // apply color controls @@ -1305,6 +1290,12 @@ static void hdmi_config_set_csc() // final compression csc.compress(2.0f); + // make sure to retain hdmi limited range + if (hdmi_limited_1) + csc = csc * mat4x4(hdmi_limited_1_coeffs); + else if (hdmi_limited_2) + csc = csc * mat4x4(hdmi_limited_2_coeffs); + // finally, apply a fixed multiplier to get it in // correct range for ADV7513 chip for (size_t i = 0; i < 12; i++) @@ -1532,6 +1523,13 @@ static void hdmi_config_init() static void hdmi_config_set_hdr() { + // Grab desired nits values + uint8_t maxNitsLSB = cfg.hdr_max_nits & 0xFF; + uint8_t maxNitsMSB = (cfg.hdr_max_nits >> 8) & 0xFF; + + uint8_t avgNitsLSB = cfg.hdr_avg_nits & 0xFF; + uint8_t avgNitsMSB = (cfg.hdr_avg_nits >> 8) & 0xFF; + // CTA-861-G: 6.9 Dynamic Range and Mastering InfoFrame // Uses BT2020 RGB primaries and white point chromacity // Max Lum: 1000cd/m2, Min Lum: 0cd/m2, MaxCLL: 1000cd/m2 @@ -1543,7 +1541,7 @@ static void hdmi_config_set_hdr() 0x87, 0x01, 0x1a, - (cfg.hdr == 1 ? uint8_t(0x27) : uint8_t(0x28)), + 0x00, // Checksum, calculate later (cfg.hdr == 1 ? uint8_t(0x03) : uint8_t(0x02)), 0x48, 0x8a, @@ -1562,16 +1560,26 @@ static void hdmi_config_set_hdr() 0x42, 0x40, 0x00, - 0xe8, - 0x03, - 0x32, + maxNitsLSB, + maxNitsMSB, + 0x01, 0x00, - 0xe8, - 0x03, - 0xfa, - 0x00 + maxNitsLSB, + maxNitsMSB, + avgNitsLSB, + avgNitsMSB }; + // now we calculate the checksum for this packet (2s complement sum) + uint16_t checksum = 0; + for (uint i = 0; i < sizeof(hdr_data); i++) + checksum += hdr_data[i]; + + checksum = checksum & 0xFF; + checksum = ~checksum + 1; + + hdr_data[3] = checksum; + if (cfg.hdr == 0) { hdmi_config_set_spare(1, false);