diff options
author | Drew DeVault <sir@cmpwn.com> | 2018-07-07 08:58:17 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-07-07 08:58:17 -0700 |
commit | be54278207f5099b77a538e3043758aa59e5c998 (patch) | |
tree | 8e322b1c600afa6fd56a325d20e00d0ec054e85b | |
parent | 7c6588d7ae0b260aedc61da58eb6bf153b35ca94 (diff) | |
parent | 60a83e99f4dc930d7d4ed5999f49967a72b7df32 (diff) |
Merge pull request #1095 from agx/output-add-mode
Allow to add additional modes to outputs
-rw-r--r-- | backend/drm/drm.c | 27 | ||||
-rw-r--r-- | include/backend/drm/drm.h | 4 | ||||
-rw-r--r-- | include/rootston/config.h | 7 | ||||
-rw-r--r-- | rootston/config.c | 59 | ||||
-rw-r--r-- | rootston/output.c | 14 | ||||
-rw-r--r-- | rootston/rootston.ini.example | 7 |
6 files changed, 117 insertions, 1 deletions
diff --git a/backend/drm/drm.c b/backend/drm/drm.c index ae462568..05d3d1bd 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -566,6 +566,33 @@ error_conn: return false; } +bool wlr_drm_connector_add_mode(struct wlr_output *output, + const drmModeModeInfo *modeinfo) { + struct wlr_drm_connector *conn = (struct wlr_drm_connector *)output; + + assert(modeinfo); + if (modeinfo->type != DRM_MODE_TYPE_USERDEF) { + return false; + } + + struct wlr_drm_mode *mode = calloc(1, sizeof(*mode)); + if (!mode) { + return false; + } + memcpy(&mode->drm_mode, modeinfo, sizeof(*modeinfo)); + + mode->wlr_mode.width = mode->drm_mode.hdisplay; + mode->wlr_mode.height = mode->drm_mode.vdisplay; + mode->wlr_mode.refresh = mode->drm_mode.vrefresh; + + wlr_log(L_INFO, "Registered custom mode " + "%"PRId32"x%"PRId32"@%"PRId32, + mode->wlr_mode.width, mode->wlr_mode.height, + mode->wlr_mode.refresh); + wl_list_insert(&conn->output.modes, &mode->wlr_mode.link); + return true; +} + static void drm_connector_transform(struct wlr_output *output, enum wl_output_transform transform) { output->transform = transform; diff --git a/include/backend/drm/drm.h b/include/backend/drm/drm.h index 5d6ff231..416507ea 100644 --- a/include/backend/drm/drm.h +++ b/include/backend/drm/drm.h @@ -143,5 +143,9 @@ void restore_drm_outputs(struct wlr_drm_backend *drm); void scan_drm_connectors(struct wlr_drm_backend *state); int handle_drm_event(int fd, uint32_t mask, void *data); void enable_drm_connector(struct wlr_output *output, bool enable); +/** + * Add mode to the list of available modes + */ +bool wlr_drm_connector_add_mode(struct wlr_output *output, const drmModeModeInfo *mode); #endif diff --git a/include/rootston/config.h b/include/rootston/config.h index 97a8baab..86699c6a 100644 --- a/include/rootston/config.h +++ b/include/rootston/config.h @@ -1,11 +1,17 @@ #ifndef ROOTSTON_CONFIG_H #define ROOTSTON_CONFIG_H +#include <xf86drmMode.h> #include <wlr/types/wlr_input_device.h> #include <wlr/types/wlr_output_layout.h> #define ROOTS_CONFIG_DEFAULT_SEAT_NAME "seat0" +struct roots_output_mode_config { + drmModeModeInfo info; + struct wl_list link; +}; + struct roots_output_config { char *name; bool enable; @@ -17,6 +23,7 @@ struct roots_output_config { int width, height; float refresh_rate; } mode; + struct wl_list modes; }; struct roots_device_config { diff --git a/rootston/config.c b/rootston/config.c index 9a4d77fd..7ef5e629 100644 --- a/rootston/config.c +++ b/rootston/config.c @@ -116,6 +116,51 @@ static uint32_t parse_modifier(const char *symname) { } } +static bool parse_modeline(const char *s, drmModeModeInfo *mode) { + char hsync[16]; + char vsync[16]; + float fclock; + + mode->type = DRM_MODE_TYPE_USERDEF; + + if (sscanf(s, "%f %hd %hd %hd %hd %hd %hd %hd %hd %15s %15s", + &fclock, + &mode->hdisplay, + &mode->hsync_start, + &mode->hsync_end, + &mode->htotal, + &mode->vdisplay, + &mode->vsync_start, + &mode->vsync_end, + &mode->vtotal, hsync, vsync) != 11) { + return false; + } + + mode->clock = fclock * 1000; + mode->vrefresh = mode->clock * 1000.0 * 1000.0 + / mode->htotal / mode->vtotal; + if (strcasecmp(hsync, "+hsync") == 0) { + mode->flags |= DRM_MODE_FLAG_PHSYNC; + } else if (strcasecmp(hsync, "-hsync") == 0) { + mode->flags |= DRM_MODE_FLAG_NHSYNC; + } else { + return false; + } + + if (strcasecmp(vsync, "+vsync") == 0) { + mode->flags |= DRM_MODE_FLAG_PVSYNC; + } else if (strcasecmp(vsync, "-vsync") == 0) { + mode->flags |= DRM_MODE_FLAG_NVSYNC; + } else { + return false; + } + + snprintf(mode->name, sizeof(mode->name), "%dx%d@%d", + mode->hdisplay, mode->vdisplay, mode->vrefresh / 1000); + + return true; +} + void add_binding_config(struct wl_list *bindings, const char* combination, const char* command) { struct roots_binding_config *bc = @@ -269,6 +314,7 @@ static int config_ini_handler(void *user, const char *section, const char *name, oc->transform = WL_OUTPUT_TRANSFORM_NORMAL; oc->scale = 1; oc->enable = true; + wl_list_init(&oc->modes); wl_list_insert(&config->outputs, &oc->link); } @@ -322,6 +368,15 @@ static int config_ini_handler(void *user, const char *section, const char *name, wlr_log(L_DEBUG, "Configured output %s with mode %dx%d@%f", oc->name, oc->mode.width, oc->mode.height, oc->mode.refresh_rate); + } else if (strcmp(name, "modeline") == 0) { + struct roots_output_mode_config *mode = calloc(1, sizeof(*mode)); + + if (parse_modeline(value, &mode->info)) { + wl_list_insert(&oc->modes, &mode->link); + } else { + free(mode); + wlr_log(L_ERROR, "Invalid modeline: %s", value); + } } } else if (strncmp(cursor_prefix, section, strlen(cursor_prefix)) == 0) { const char *seat_name = section + strlen(cursor_prefix); @@ -459,6 +514,10 @@ struct roots_config *roots_config_create_from_args(int argc, char *argv[]) { void roots_config_destroy(struct roots_config *config) { struct roots_output_config *oc, *otmp = NULL; wl_list_for_each_safe(oc, otmp, &config->outputs, link) { + struct roots_output_mode_config *omc, *omctmp = NULL; + wl_list_for_each_safe(omc, omctmp, &oc->modes, link) { + free(omc); + } free(oc->name); free(oc); } diff --git a/rootston/output.c b/rootston/output.c index fd7df99c..e3b03984 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -16,6 +16,7 @@ #include "rootston/layers.h" #include "rootston/output.h" #include "rootston/server.h" +#include "backend/drm/drm.h" /** * Rotate a child's position relative to a parent. The parent size is (pw, ph), @@ -821,7 +822,7 @@ void handle_new_output(struct wl_listener *listener, void *data) { wlr_output->model, wlr_output->serial, wlr_output->phys_width, wlr_output->phys_height); - if (wl_list_length(&wlr_output->modes) > 0) { + if (!wl_list_empty(&wlr_output->modes)) { struct wlr_output_mode *mode = wl_container_of((&wlr_output->modes)->prev, mode, link); wlr_output_set_mode(wlr_output, mode); @@ -857,6 +858,17 @@ void handle_new_output(struct wl_listener *listener, void *data) { roots_config_get_output(config, wlr_output); if (output_config) { if (output_config->enable) { + struct roots_output_mode_config *mode_config; + + if (wlr_output_is_drm(wlr_output)) { + wl_list_for_each(mode_config, &output_config->modes, link) { + wlr_drm_connector_add_mode(wlr_output, &mode_config->info); + } + } else { + if (!wl_list_empty(&output_config->modes)) { + wlr_log(L_ERROR, "Can only add modes for DRM backend"); + } + } if (output_config->mode.width) { set_mode(wlr_output, output_config); } diff --git a/rootston/rootston.ini.example b/rootston/rootston.ini.example index 556cbefb..bb0efa44 100644 --- a/rootston/rootston.ini.example +++ b/rootston/rootston.ini.example @@ -19,6 +19,13 @@ y = 0 # and rotate by specified angle rotate = 90 +# Additional video mode to add +# Format is generated by cvt and is documented in x.org.conf(5) +modeline = 87.25 720 776 848 976 1440 1443 1453 1493 -hsync +vsync +modeline = 65.13 768 816 896 1024 1024 1025 1028 1060 -HSync +VSync +# Select one of the above modes +mode = 768x1024 + [cursor] # Restrict cursor movements to single output map-to-output = VGA-1 |