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
This commit is contained in:
@@ -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.
|
||||
|
||||
2
cfg.cpp
2
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 },
|
||||
|
||||
24
dv_dac.txt
Normal file
24
dv_dac.txt
Normal file
@@ -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
|
||||
31
dv_dac_user.txt
Normal file
31
dv_dac_user.txt
Normal file
@@ -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
|
||||
156
video.cpp
156
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");
|
||||
|
||||
Reference in New Issue
Block a user