mirror of
https://github.com/libretro/RetroArch
synced 2025-03-29 22:20:21 +00:00
(KMS/DRM) add support for custom modes from hdmi timings
This commit is contained in:
parent
bcc7dde90d
commit
0082806620
@ -1235,6 +1235,7 @@ static struct config_array_setting *populate_settings_array(settings_t *settings
|
||||
SETTING_ARRAY("twitch_stream_key", settings->arrays.twitch_stream_key, true, NULL, true);
|
||||
SETTING_ARRAY("discord_app_id", settings->arrays.discord_app_id, true, DEFAULT_DISCORD_APP_ID, true);
|
||||
SETTING_ARRAY("ai_service_url", settings->arrays.ai_service_url, true, DEFAULT_AI_SERVICE_URL, true);
|
||||
SETTING_ARRAY("crt_switch_timings", settings->arrays.crt_switch_timings, false, NULL, true);
|
||||
|
||||
*size = count;
|
||||
|
||||
|
@ -367,6 +367,8 @@ typedef struct settings
|
||||
char twitch_stream_key[PATH_MAX_LENGTH];
|
||||
char discord_app_id[PATH_MAX_LENGTH];
|
||||
char ai_service_url[PATH_MAX_LENGTH];
|
||||
|
||||
char crt_switch_timings[255];
|
||||
} arrays;
|
||||
|
||||
struct
|
||||
|
@ -90,7 +90,73 @@ struct drm_fb
|
||||
uint32_t fb_id;
|
||||
};
|
||||
|
||||
// https://www.raspberrypi.org/documentation/configuration/config-txt/video.md
|
||||
typedef struct hdmi_timings
|
||||
{
|
||||
int h_active_pixels; // horizontal pixels (width)
|
||||
int h_sync_polarity; // invert hsync polarity
|
||||
int h_front_porch; // horizontal forward padding from DE acitve edge
|
||||
int h_sync_pulse; // hsync pulse width in pixel clocks
|
||||
int h_back_porch; // vertical back padding from DE active edge
|
||||
int v_active_lines; // vertical pixels height (lines)
|
||||
int v_sync_polarity; // invert vsync polarity
|
||||
int v_front_porch; // vertical forward padding from DE active edge
|
||||
int v_sync_pulse; // vsync pulse width in pixel clocks
|
||||
int v_back_porch; // vertical back padding from DE active edge
|
||||
int v_sync_offset_a; // leave at zero
|
||||
int v_sync_offset_b; // leave at zero
|
||||
int pixel_rep; // leave at zero
|
||||
int frame_rate; // screen refresh rate in Hz
|
||||
int interlaced; // leave at zero
|
||||
int pixel_freq; // clock frequency (width*height*framerate)
|
||||
int aspect_ratio; // *
|
||||
} hdmi_timings_t;
|
||||
|
||||
static enum gfx_ctx_api drm_api = GFX_CTX_NONE;
|
||||
static drmModeModeInfo crt_switch_mode;
|
||||
|
||||
static bool gfx_ctx_drm_timings_to_mode(const char *timings_str, drmModeModeInfoPtr modeInfo)
|
||||
{
|
||||
int ret;
|
||||
hdmi_timings_t timings;
|
||||
|
||||
if(timings_str != NULL && modeInfo != NULL) {
|
||||
ret = sscanf(timings_str, "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d",
|
||||
&timings.h_active_pixels, &timings.h_sync_polarity, &timings.h_front_porch,
|
||||
&timings.h_sync_pulse, &timings.h_back_porch,
|
||||
&timings.v_active_lines, &timings.v_sync_polarity, &timings.v_front_porch,
|
||||
&timings.v_sync_pulse, &timings.v_back_porch,
|
||||
&timings.v_sync_offset_a, &timings.v_sync_offset_b, &timings.pixel_rep, &timings.frame_rate,
|
||||
&timings.interlaced, &timings.pixel_freq, &timings.aspect_ratio);
|
||||
if (ret != 17) {
|
||||
RARCH_ERR("[KMS/EGL]: malformed custom mode: %s\n", timings_str);
|
||||
return false;
|
||||
}
|
||||
|
||||
memset(modeInfo, 0, sizeof(drmModeModeInfo));
|
||||
modeInfo->clock = timings.pixel_freq / 1000;
|
||||
modeInfo->hdisplay = timings.h_active_pixels;
|
||||
modeInfo->hsync_start = modeInfo->hdisplay + timings.h_front_porch;
|
||||
modeInfo->hsync_end = modeInfo->hsync_start + timings.h_sync_pulse;
|
||||
modeInfo->htotal = modeInfo->hsync_end + timings.h_back_porch;
|
||||
modeInfo->hskew = 0; // TODO: ??
|
||||
modeInfo->vdisplay = timings.v_active_lines;
|
||||
modeInfo->vsync_start = modeInfo->vdisplay + (timings.v_front_porch * (timings.interlaced ? 2 : 1));
|
||||
modeInfo->vsync_end = modeInfo->vsync_start + (timings.v_sync_pulse * (timings.interlaced ? 2 : 1));
|
||||
modeInfo->vtotal = modeInfo->vsync_end + (timings.v_back_porch * (timings.interlaced ? 2 : 1));
|
||||
modeInfo->vscan = 0; // TODO: ??
|
||||
modeInfo->vrefresh = timings.frame_rate;
|
||||
modeInfo->flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC
|
||||
| (timings.interlaced ? DRM_MODE_FLAG_INTERLACE : 0);
|
||||
modeInfo->type = 0;
|
||||
snprintf(modeInfo->name, DRM_DISPLAY_MODE_LEN, "CRT_%ux%u_%u",
|
||||
modeInfo->hdisplay, modeInfo->vdisplay, modeInfo->vrefresh);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
|
||||
{
|
||||
@ -611,6 +677,8 @@ error:
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
static bool gfx_ctx_drm_set_video_mode(void *data,
|
||||
unsigned width, unsigned height,
|
||||
bool fullscreen)
|
||||
@ -622,6 +690,7 @@ static bool gfx_ctx_drm_set_video_mode(void *data,
|
||||
settings_t *settings = config_get_ptr();
|
||||
unsigned black_frame_insertion = settings->uints.video_black_frame_insertion;
|
||||
float video_refresh_rate = settings->floats.video_refresh_rate;
|
||||
char *crt_switch_timings = settings->arrays.crt_switch_timings;
|
||||
|
||||
if (!drm)
|
||||
return false;
|
||||
@ -640,28 +709,36 @@ static bool gfx_ctx_drm_set_video_mode(void *data,
|
||||
g_drm_mode = &g_drm_connector->modes[0];
|
||||
else
|
||||
{
|
||||
/* Try to match refresh_rate as closely as possible.
|
||||
*
|
||||
* Lower resolutions tend to have multiple supported
|
||||
* refresh rates as well.
|
||||
*/
|
||||
float minimum_fps_diff = 0.0f;
|
||||
|
||||
/* Find best match. */
|
||||
for (i = 0; i < g_drm_connector->count_modes; i++)
|
||||
// check for custom crt hdmi timings
|
||||
if(!string_is_empty(crt_switch_timings)
|
||||
&& gfx_ctx_drm_timings_to_mode(crt_switch_timings, &crt_switch_mode))
|
||||
{
|
||||
float diff;
|
||||
if (width != g_drm_connector->modes[i].hdisplay ||
|
||||
RARCH_LOG("[KMS/EGL]: custom mode requested: %s\n", crt_switch_mode.name);
|
||||
g_drm_mode = &crt_switch_mode;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Try to match refresh_rate as closely as possible.
|
||||
*
|
||||
* Lower resolutions tend to have multiple supported
|
||||
* refresh rates as well.
|
||||
*/
|
||||
float minimum_fps_diff = 0.0f;
|
||||
|
||||
/* Find best match. */
|
||||
for (i = 0; i < g_drm_connector->count_modes; i++) {
|
||||
float diff;
|
||||
if (width != g_drm_connector->modes[i].hdisplay ||
|
||||
height != g_drm_connector->modes[i].vdisplay)
|
||||
continue;
|
||||
continue;
|
||||
|
||||
diff = fabsf(refresh_mod * g_drm_connector->modes[i].vrefresh
|
||||
- video_refresh_rate);
|
||||
diff = fabsf(refresh_mod * g_drm_connector->modes[i].vrefresh
|
||||
- video_refresh_rate);
|
||||
|
||||
if (!g_drm_mode || diff < minimum_fps_diff)
|
||||
{
|
||||
g_drm_mode = &g_drm_connector->modes[i];
|
||||
minimum_fps_diff = diff;
|
||||
if (!g_drm_mode || diff < minimum_fps_diff) {
|
||||
g_drm_mode = &g_drm_connector->modes[i];
|
||||
minimum_fps_diff = diff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user