From 4b591f58fc1ab6d644540b468763b09bcf7cd5f3 Mon Sep 17 00:00:00 2001 From: misteraddons <51079966+misteraddons@users.noreply.github.com> Date: Fri, 12 Sep 2025 00:08:50 -0600 Subject: [PATCH] Automatic Direct Video (#1035) * Simple Auto Direct Video direct_video=2 Checks for 1024x768 HDMI resolution and sets direct_video=1 No hot plug detect No EDID parsing No device whitelist No hdmi_limited set based on EDID whitelist * Add EDID detection and set hdmi_limited for common DACs - AG6200 sets hdmi_limited=2 - CS5213 sets hdmi_limited=0 * Fix logic to pass normal EDID resolution if not 1024x768 * Update MiSTer.ini * Remove 1024x768 resolution check - Only use mfg_id from EDID to identify known compatible DACs * Add DAC id and settings to dv_dac.txt and dv_dac_user.txt - mfg_id - rgb range - hdmi_audio_96khz - composite_sync: 0, 1, or "" (default is "") - dv_dac_user.txt for HDMI video upscalers that support direct video - device commented out by default --- MiSTer.ini | 3 + cfg.cpp | 2 +- dv_dac.txt | 24 ++++++++ dv_dac_user.txt | 31 ++++++++++ video.cpp | 156 ++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 215 insertions(+), 1 deletion(-) create mode 100644 dv_dac.txt create mode 100644 dv_dac_user.txt diff --git a/MiSTer.ini b/MiSTer.ini index e83e484..7f6ea88 100644 --- a/MiSTer.ini +++ b/MiSTer.ini @@ -23,6 +23,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. + ; 2 - auto-mode for HDMI DACs that report 1024x768 resolution (AG6200, CS5213). + ; Power cycle when switching between HDMI displays and DACs. No hot-plug detection. + hdr=0 ; 1 - enable HDR using HLG (recommended for most users) ; 2 - enable HDR using the DCI P3 color space (use color controls to tweak, suggestion: set saturation to 80). fb_size=0 ; 0 - automatic, 1 - full size, 2 - 1/2 of resolution, 4 - 1/4 of resolution. diff --git a/cfg.cpp b/cfg.cpp index fe00eef..8c3cb73 100644 --- a/cfg.cpp +++ b/cfg.cpp @@ -65,7 +65,7 @@ static const ini_var_t ini_vars[] = { "FB_SIZE", (void*)(&(cfg.fb_size)), UINT8, 0, 4 }, { "FB_TERMINAL", (void*)(&(cfg.fb_terminal)), UINT8, 0, 1 }, { "OSD_TIMEOUT", (void*)(&(cfg.osd_timeout)), INT16, 0, 3600 }, - { "DIRECT_VIDEO", (void*)(&(cfg.direct_video)), UINT8, 0, 1 }, + { "DIRECT_VIDEO", (void*)(&(cfg.direct_video)), UINT8, 0, 2 }, { "OSD_ROTATE", (void*)(&(cfg.osd_rotate)), UINT8, 0, 2 }, { "DEADZONE", (void*)(&(cfg.controller_deadzone)), STRINGARR, sizeof(cfg.controller_deadzone) / sizeof(*cfg.controller_deadzone), sizeof(*cfg.controller_deadzone) }, { "GAMEPAD_DEFAULTS", (void*)(&(cfg.gamepad_defaults)), UINT8, 0, 1 }, diff --git a/dv_dac.txt b/dv_dac.txt new file mode 100644 index 0000000..e54b44c --- /dev/null +++ b/dv_dac.txt @@ -0,0 +1,24 @@ +# Direct Video DAC Configuration File +# Format: mfg_id,hdmi_limited,hdmi_audio_96k,composite_sync,name +# +# mfg_id: Manufacturer ID from EDID bytes 0x08-0x09 (hex, e.g. 0x48F4) +# This is the raw 16-bit value from EDID, NOT the decoded 3-letter code +# hdmi_limited: 0=full range RGB (0-255) +# 1=limited range RGB (16-235) +# 2=limited range RGB (16-255) +# hdmi_audio_96k: 0=48kHz audio, 1=96kHz audio +# composite_sync: 0=disable composite sync, 1=enable composite sync, blank=use MiSTer.ini setting +# name: Description of the DAC (optional, for logging purposes) +# +# The mfg_id comes from EDID bytes: +# Byte 0x08: High byte of manufacturer ID +# Byte 0x09: Low byte of manufacturer ID +# Combined as: (byte_08 << 8) | byte_09 +# +# Examples: +# 0x48F4,0,0,,Full-range CS5213 DAC +# 0x04EF,2,0,1,Limited-range AG6200 DAC + +# Known DACs +0x48F4,0,0,,Full-range CS5213 DAC +0x04EF,2,0,,Limited-range AG6200 DAC diff --git a/dv_dac_user.txt b/dv_dac_user.txt new file mode 100644 index 0000000..4ba782d --- /dev/null +++ b/dv_dac_user.txt @@ -0,0 +1,31 @@ +# User Direct Video DAC Configuration File +# This file allows users to add their own DAC configurations +# or override settings from dv_dac.txt +# +# Format: mfg_id,hdmi_limited,hdmi_audio_96k,composite_sync,name +# +# mfg_id: Manufacturer ID from EDID bytes 0x08-0x09 (hex, e.g. 0x48F4) +# This is the raw 16-bit value from EDID, NOT the decoded 3-letter code +# hdmi_limited: 0=full range RGB (0-255) +# 1=limited range RGB (16-235) +# 2=limited range RGB (16-255) +# hdmi_audio_96k: 0=48kHz audio, 1=96kHz audio +# composite_sync: 0=disable composite sync, 1=enable composite sync, blank=use MiSTer.ini setting +# name: Description of the DAC (optional, for logging purposes) +# +# The mfg_id comes from EDID bytes: +# Byte 0x08: High byte of manufacturer ID +# Byte 0x09: Low byte of manufacturer ID +# Combined as: (byte_08 << 8) | byte_09 +# +# Examples: +# 0x40D8,0,1,,PixelFX Morph (full range, use MiSTer.ini csync setting) +# 0x1234,1,1,1,Custom DAC (limited 16-235, force composite sync on) +# 0x5678,2,0,0,Another DAC (limited 16-255, force composite sync off) +# +# Note: Entries in this file will override any matching mfg_id from dv_dac.txt +# +# Known video upscalers that support direct video +# (remove "# " in front of device if you want to use automatic direct video mode): +# 0x40D8,0,1,1,PixelFX Morph 4K +# 0x4A8B,0,1,1,RetroTink 4K Pro diff --git a/video.cpp b/video.cpp index a10970b..7726d99 100644 --- a/video.cpp +++ b/video.cpp @@ -2425,8 +2425,164 @@ static void fb_init() spi_uio_cmd16(UIO_SET_FBUF, 0); } +// Structure to hold DAC configuration +struct dac_config { + uint16_t mfg_id; + uint8_t hdmi_limited; + uint8_t hdmi_audio_96k; + int8_t composite_sync; // -1=use MiSTer.ini, 0=force off, 1=force on + char name[64]; +}; + +static dac_config dac_configs[32]; +static int dac_config_count = 0; + +static void load_dac_file(const char *filename) +{ + fileTextReader reader; + const char *line; + + if (!FileOpenTextReader(&reader, filename)) { + return; + } + + printf("Loading DAC configuration from %s\n", filename); + + while ((line = FileReadLine(&reader)) && dac_config_count < 32) { + // Skip comments and empty lines + if (line[0] == '#' || line[0] == '\n' || line[0] == '\r' || line[0] == '\0') continue; + + // Parse format: mfg_id,hdmi_limited,hdmi_audio_96k,composite_sync,name + // Example: 0x48F4,0,0,,Full-range CS5213 DAC + unsigned int mfg, limited, audio_96k = 0; + char name[64] = {0}; + char csync_str[16] = {0}; + int8_t csync = -1; // Default to use MiSTer.ini setting + + // Parse with optional composite_sync field + int fields = sscanf(line, "%x,%u,%u,%15[^,],%63[^\n]", &mfg, &limited, &audio_96k, csync_str, name); + if (fields >= 2) { + // Parse composite sync field if present + if (fields >= 4 && strlen(csync_str) > 0) { + csync = (csync_str[0] == '1') ? 1 : 0; + } + // Check if this mfg_id already exists and update it + bool found = false; + for (int i = 0; i < dac_config_count; i++) { + if (dac_configs[i].mfg_id == mfg) { + dac_configs[i].hdmi_limited = limited; + dac_configs[i].hdmi_audio_96k = audio_96k; + dac_configs[i].composite_sync = csync; + strncpy(dac_configs[i].name, name, 63); + printf(" Updated DAC: mfg=0x%04X, hdmi_limited=%d, hdmi_audio_96k=%d, csync=%d, %s\n", + mfg, limited, audio_96k, csync, name); + found = true; + break; + } + } + + if (!found) { + dac_configs[dac_config_count].mfg_id = mfg; + dac_configs[dac_config_count].hdmi_limited = limited; + dac_configs[dac_config_count].hdmi_audio_96k = audio_96k; + dac_configs[dac_config_count].composite_sync = csync; + strncpy(dac_configs[dac_config_count].name, name, 63); + printf(" DAC[%d]: mfg=0x%04X, hdmi_limited=%d, hdmi_audio_96k=%d, csync=%d, %s\n", + dac_config_count, mfg, limited, audio_96k, csync, name); + dac_config_count++; + } + } + } +} + +static void load_dac_config() +{ + dac_config_count = 0; + + // Try to load main DAC file + load_dac_file("dv_dac.txt"); + + // Load user DAC file (overrides/adds to main file) + load_dac_file("dv_dac_user.txt"); + + if (dac_config_count == 0) { + // If no files found, use built-in defaults + dac_configs[0].mfg_id = 0x48F4; + dac_configs[0].hdmi_limited = 0; + dac_configs[0].hdmi_audio_96k = 0; + dac_configs[0].composite_sync = -1; + strcpy(dac_configs[0].name, "Full-range DAC (built-in)"); + + dac_configs[1].mfg_id = 0x04EF; + dac_configs[1].hdmi_limited = 2; + dac_configs[1].hdmi_audio_96k = 0; + dac_configs[1].composite_sync = -1; + strcpy(dac_configs[1].name, "Limited-range DAC (built-in)"); + + dac_config_count = 2; + printf("No DAC config files found, using built-in defaults\n"); + } + + printf("Total: %d DAC configurations loaded\n", dac_config_count); +} + +static int should_auto_enable_direct_video() +{ + // Load DAC config on first call + static bool dac_config_loaded = false; + if (!dac_config_loaded) { + load_dac_config(); + dac_config_loaded = true; + } + + // Read EDID if not already valid + if (!is_edid_valid()) { + get_active_edid(); + } + + if (!is_edid_valid()) return 0; + + // Check manufacturer ID (bytes 0x08-0x09) + uint16_t mfg_id = (edid[0x08] << 8) | edid[0x09]; + + // Check against known DACs from config + for (int i = 0; i < dac_config_count; i++) { + if (mfg_id == dac_configs[i].mfg_id) { + printf("EDID: Detected known DAC: %s\n", dac_configs[i].name); + printf("EDID: Auto-enabling direct video with hdmi_limited=%d, hdmi_audio_96k=%d\n", + dac_configs[i].hdmi_limited, dac_configs[i].hdmi_audio_96k); + cfg.hdmi_limited = dac_configs[i].hdmi_limited; + cfg.hdmi_audio_96k = dac_configs[i].hdmi_audio_96k; + + // Set composite sync if specified + if (dac_configs[i].composite_sync >= 0) { + cfg.csync = dac_configs[i].composite_sync; + printf("EDID: Auto-setting composite_sync=%d\n", dac_configs[i].composite_sync); + } else { + printf("EDID: Composite sync setting deferred to MiSTer.ini\n"); + } + return 1; + } + } + + // Not a known DAC, don't enable direct video + return 0; +} + static void video_mode_load() { + // Auto-detect and enable direct video if configured + if (cfg.direct_video == 2) { + if (should_auto_enable_direct_video()) { + printf("Auto-enabling direct video for known DAC.\n"); + // Enable direct video, preserve all other user settings + cfg.direct_video = 1; + } else { + // Not a DAC, use normal HDMI mode + cfg.direct_video = 0; + } + } + if (cfg.direct_video && cfg.vsync_adjust) { printf("Disabling vsync_adjust because of enabled direct video.\n");