Add output modeline command

Only works with DRM backend.
This commit is contained in:
David Rosca 2021-07-18 12:05:47 +02:00 committed by Simon Ser
parent daaec72ac0
commit 57d6f6f19e
6 changed files with 94 additions and 1 deletions

View file

@ -282,6 +282,7 @@ sway_cmd output_cmd_dpms;
sway_cmd output_cmd_enable; sway_cmd output_cmd_enable;
sway_cmd output_cmd_max_render_time; sway_cmd output_cmd_max_render_time;
sway_cmd output_cmd_mode; sway_cmd output_cmd_mode;
sway_cmd output_cmd_modeline;
sway_cmd output_cmd_position; sway_cmd output_cmd_position;
sway_cmd output_cmd_scale; sway_cmd output_cmd_scale;
sway_cmd output_cmd_scale_filter; sway_cmd output_cmd_scale_filter;

View file

@ -8,6 +8,7 @@
#include <wlr/types/wlr_tablet_tool.h> #include <wlr/types/wlr_tablet_tool.h>
#include <wlr/util/box.h> #include <wlr/util/box.h>
#include <xkbcommon/xkbcommon.h> #include <xkbcommon/xkbcommon.h>
#include <xf86drmMode.h>
#include "../include/config.h" #include "../include/config.h"
#include "list.h" #include "list.h"
#include "swaynag.h" #include "swaynag.h"
@ -257,6 +258,7 @@ struct output_config {
int width, height; int width, height;
float refresh_rate; float refresh_rate;
int custom_mode; int custom_mode;
drmModeModeInfo drm_mode;
int x, y; int x, y;
float scale; float scale;
enum scale_filter_mode scale_filter; enum scale_filter_mode scale_filter;

View file

@ -15,6 +15,7 @@ static const struct cmd_handler output_handlers[] = {
{ "enable", output_cmd_enable }, { "enable", output_cmd_enable },
{ "max_render_time", output_cmd_max_render_time }, { "max_render_time", output_cmd_max_render_time },
{ "mode", output_cmd_mode }, { "mode", output_cmd_mode },
{ "modeline", output_cmd_modeline },
{ "pos", output_cmd_position }, { "pos", output_cmd_position },
{ "position", output_cmd_position }, { "position", output_cmd_position },
{ "res", output_cmd_mode }, { "res", output_cmd_mode },

View file

@ -20,6 +20,9 @@ struct cmd_results *output_cmd_mode(int argc, char **argv) {
output->custom_mode = 0; output->custom_mode = 0;
} }
// Reset custom modeline, if any
output->drm_mode.type = 0;
char *end; char *end;
output->width = strtol(*argv, &end, 10); output->width = strtol(*argv, &end, 10);
if (*end) { if (*end) {
@ -58,3 +61,58 @@ struct cmd_results *output_cmd_mode(int argc, char **argv) {
return NULL; return NULL;
} }
static bool parse_modeline(char **argv, drmModeModeInfo *mode) {
mode->type = DRM_MODE_TYPE_USERDEF;
mode->clock = strtof(argv[0], NULL) * 1000;
mode->hdisplay = strtol(argv[1], NULL, 10);
mode->hsync_start = strtol(argv[2], NULL, 10);
mode->hsync_end = strtol(argv[3], NULL, 10);
mode->htotal = strtol(argv[4], NULL, 10);
mode->vdisplay = strtol(argv[5], NULL, 10);
mode->vsync_start = strtol(argv[6], NULL, 10);
mode->vsync_end = strtol(argv[7], NULL, 10);
mode->vtotal = strtol(argv[8], NULL, 10);
mode->vrefresh = mode->clock * 1000.0 * 1000.0
/ mode->htotal / mode->vtotal;
if (strcasecmp(argv[9], "+hsync") == 0) {
mode->flags |= DRM_MODE_FLAG_PHSYNC;
} else if (strcasecmp(argv[9], "-hsync") == 0) {
mode->flags |= DRM_MODE_FLAG_NHSYNC;
} else {
return false;
}
if (strcasecmp(argv[10], "+vsync") == 0) {
mode->flags |= DRM_MODE_FLAG_PVSYNC;
} else if (strcasecmp(argv[10], "-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;
}
struct cmd_results *output_cmd_modeline(int argc, char **argv) {
if (!config->handler_context.output_config) {
return cmd_results_new(CMD_FAILURE, "Missing output config");
}
if (!argc) {
return cmd_results_new(CMD_INVALID, "Missing modeline argument.");
}
struct output_config *output = config->handler_context.output_config;
if (argc != 11 || !parse_modeline(argv, &output->drm_mode)) {
return cmd_results_new(CMD_INVALID, "Invalid modeline");
}
config->handler_context.leftovers.argc = argc - 12;
config->handler_context.leftovers.argv = argv + 12;
return NULL;
}

View file

@ -8,6 +8,7 @@
#include <wlr/types/wlr_cursor.h> #include <wlr/types/wlr_cursor.h>
#include <wlr/types/wlr_output_layout.h> #include <wlr/types/wlr_output_layout.h>
#include <wlr/types/wlr_output.h> #include <wlr/types/wlr_output.h>
#include <wlr/backend/drm.h>
#include "sway/config.h" #include "sway/config.h"
#include "sway/input/cursor.h" #include "sway/input/cursor.h"
#include "sway/output.h" #include "sway/output.h"
@ -58,6 +59,7 @@ struct output_config *new_output_config(const char *name) {
oc->width = oc->height = -1; oc->width = oc->height = -1;
oc->refresh_rate = -1; oc->refresh_rate = -1;
oc->custom_mode = -1; oc->custom_mode = -1;
oc->drm_mode.type = -1;
oc->x = oc->y = -1; oc->x = oc->y = -1;
oc->scale = -1; oc->scale = -1;
oc->scale_filter = SCALE_FILTER_DEFAULT; oc->scale_filter = SCALE_FILTER_DEFAULT;
@ -99,6 +101,9 @@ void merge_output_config(struct output_config *dst, struct output_config *src) {
if (src->custom_mode != -1) { if (src->custom_mode != -1) {
dst->custom_mode = src->custom_mode; dst->custom_mode = src->custom_mode;
} }
if (src->drm_mode.type != (uint32_t) -1) {
memcpy(&dst->drm_mode, &src->drm_mode, sizeof(src->drm_mode));
}
if (src->transform != -1) { if (src->transform != -1) {
dst->transform = src->transform; dst->transform = src->transform;
} }
@ -271,6 +276,18 @@ static void set_mode(struct wlr_output *output, int width, int height,
wlr_output_set_mode(output, best); wlr_output_set_mode(output, best);
} }
static void set_modeline(struct wlr_output *output, drmModeModeInfo *drm_mode) {
if (!wlr_output_is_drm(output)) {
sway_log(SWAY_ERROR, "Modeline can only be set to DRM output");
return;
}
sway_log(SWAY_DEBUG, "Assigning custom modeline to %s", output->name);
struct wlr_output_mode *mode = wlr_drm_connector_add_mode(output, drm_mode);
if (mode) {
wlr_output_set_mode(output, mode);
}
}
/* Some manufacturers hardcode the aspect-ratio of the output in the physical /* Some manufacturers hardcode the aspect-ratio of the output in the physical
* size field. */ * size field. */
static bool phys_size_is_aspect_ratio(struct wlr_output *output) { static bool phys_size_is_aspect_ratio(struct wlr_output *output) {
@ -351,7 +368,11 @@ static void queue_output_config(struct output_config *oc,
sway_log(SWAY_DEBUG, "Turning on output %s", wlr_output->name); sway_log(SWAY_DEBUG, "Turning on output %s", wlr_output->name);
wlr_output_enable(wlr_output, true); wlr_output_enable(wlr_output, true);
if (oc && oc->width > 0 && oc->height > 0) { if (oc && oc->drm_mode.type != 0 && oc->drm_mode.type != (uint32_t) -1) {
sway_log(SWAY_DEBUG, "Set %s modeline",
wlr_output->name);
set_modeline(wlr_output, &oc->drm_mode);
} else if (oc && oc->width > 0 && oc->height > 0) {
sway_log(SWAY_DEBUG, "Set %s mode to %dx%d (%f Hz)", sway_log(SWAY_DEBUG, "Set %s mode to %dx%d (%f Hz)",
wlr_output->name, oc->width, oc->height, oc->refresh_rate); wlr_output->name, oc->width, oc->height, oc->refresh_rate);
set_mode(wlr_output, oc->width, oc->height, set_mode(wlr_output, oc->width, oc->height,

View file

@ -40,6 +40,16 @@ must be separated by one space. For example:
output HDMI-A-1 mode 1920x1080@60Hz output HDMI-A-1 mode 1920x1080@60Hz
*output* <name> modeline <clock> <hdisplay> <hsync_start> <hsync_end> <htotal> <vdisplay> <vsync_start> <vsync_end> <vtotal> <hsync> <vsync>
Configures the specified output to use the given modeline. It can be
generated using *cvt*(1) and *gtf*(1) commands. See *xorg.conf*(5).
Only supported on DRM backend.
Example:
output HDMI-A-1 modeline 173.00 1920 2048 2248 2576 1080 1083 1088 1120 -hsync +vsync
*output* <name> position|pos <X> <Y> *output* <name> position|pos <X> <Y>
Places the specified output at the specific position in the global Places the specified output at the specific position in the global
coordinate space. The cursor may only be moved between immediately coordinate space. The cursor may only be moved between immediately