Merge pull request #11590 from Cpasjuste/crt_switch_timings

(KMS/DRM) add support for custom hdmi_timings / modes
This commit is contained in:
Autechre 2020-11-19 13:45:15 +01:00 committed by GitHub
commit fbd04ea76e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 109 additions and 20 deletions

View File

@ -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;

View File

@ -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

View File

@ -90,7 +90,80 @@ struct drm_fb
uint32_t fb_id;
};
/*
* https://github.com/libretro/RetroArch/pull/11590
* 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 gfx_ctx_crt_switch_mode;
/* Load custom hdmi timings from config */
bool gfx_ctx_drm_load_mode(drmModeModeInfoPtr modeInfo)
{
int ret;
hdmi_timings_t timings;
settings_t *settings = config_get_ptr();
char *crt_switch_timings = settings->arrays.crt_switch_timings;
if(modeInfo != NULL && !string_is_empty(crt_switch_timings)) {
ret = sscanf(crt_switch_timings, "%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("[DRM]: malformed mode requested: %s\n", crt_switch_timings);
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;
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 = timings.interlaced ? DRM_MODE_FLAG_INTERLACE : 0;
modeInfo->flags |= timings.v_sync_polarity ? DRM_MODE_FLAG_NVSYNC : DRM_MODE_FLAG_PVSYNC;
modeInfo->flags |= timings.h_sync_polarity ? DRM_MODE_FLAG_NHSYNC : DRM_MODE_FLAG_PHSYNC;
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)
{
@ -363,9 +436,15 @@ nextgpu:
drm_setup(fd);
/* Choose the optimal video mode for get_video_size():
- the current video mode from the CRTC
- custom timings from configuration
- else the current video mode from the CRTC
- otherwise pick first connector mode */
if (g_orig_crtc->mode_valid)
if(gfx_ctx_drm_load_mode(&gfx_ctx_crt_switch_mode))
{
drm->fb_width = gfx_ctx_crt_switch_mode.hdisplay;
drm->fb_height = gfx_ctx_crt_switch_mode.vdisplay;
}
else if (g_orig_crtc->mode_valid)
{
drm->fb_width = g_orig_crtc->mode.hdisplay;
drm->fb_height = g_orig_crtc->mode.vdisplay;
@ -640,28 +719,35 @@ 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 if custom hdmi timings were asked */
if(gfx_ctx_crt_switch_mode.vdisplay > 0)
{
float diff;
if (width != g_drm_connector->modes[i].hdisplay ||
RARCH_LOG("[DRM]: custom mode requested: %s\n", gfx_ctx_crt_switch_mode.name);
g_drm_mode = &gfx_ctx_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;
}
}
}
}