aboutsummaryrefslogtreecommitdiffstats
path: root/sway/config/output.c
diff options
context:
space:
mode:
Diffstat (limited to 'sway/config/output.c')
-rw-r--r--sway/config/output.c122
1 files changed, 106 insertions, 16 deletions
diff --git a/sway/config/output.c b/sway/config/output.c
index c9ec6745..aa4cf946 100644
--- a/sway/config/output.c
+++ b/sway/config/output.c
@@ -1,5 +1,6 @@
1#define _POSIX_C_SOURCE 200809L 1#define _POSIX_C_SOURCE 200809L
2#include <assert.h> 2#include <assert.h>
3#include <drm_fourcc.h>
3#include <stdbool.h> 4#include <stdbool.h>
4#include <string.h> 5#include <string.h>
5#include <sys/socket.h> 6#include <sys/socket.h>
@@ -8,6 +9,7 @@
8#include <wlr/types/wlr_cursor.h> 9#include <wlr/types/wlr_cursor.h>
9#include <wlr/types/wlr_output_layout.h> 10#include <wlr/types/wlr_output_layout.h>
10#include <wlr/types/wlr_output.h> 11#include <wlr/types/wlr_output.h>
12#include <wlr/backend/drm.h>
11#include "sway/config.h" 13#include "sway/config.h"
12#include "sway/input/cursor.h" 14#include "sway/input/cursor.h"
13#include "sway/output.h" 15#include "sway/output.h"
@@ -25,8 +27,10 @@ int output_name_cmp(const void *item, const void *data) {
25void output_get_identifier(char *identifier, size_t len, 27void output_get_identifier(char *identifier, size_t len,
26 struct sway_output *output) { 28 struct sway_output *output) {
27 struct wlr_output *wlr_output = output->wlr_output; 29 struct wlr_output *wlr_output = output->wlr_output;
28 snprintf(identifier, len, "%s %s %s", wlr_output->make, wlr_output->model, 30 snprintf(identifier, len, "%s %s %s",
29 wlr_output->serial); 31 wlr_output->make ? wlr_output->make : "Unknown",
32 wlr_output->model ? wlr_output->model : "Unknown",
33 wlr_output->serial ? wlr_output->serial : "Unknown");
30} 34}
31 35
32const char *sway_output_scale_filter_to_string(enum scale_filter_mode scale_filter) { 36const char *sway_output_scale_filter_to_string(enum scale_filter_mode scale_filter) {
@@ -58,6 +62,7 @@ struct output_config *new_output_config(const char *name) {
58 oc->width = oc->height = -1; 62 oc->width = oc->height = -1;
59 oc->refresh_rate = -1; 63 oc->refresh_rate = -1;
60 oc->custom_mode = -1; 64 oc->custom_mode = -1;
65 oc->drm_mode.type = -1;
61 oc->x = oc->y = -1; 66 oc->x = oc->y = -1;
62 oc->scale = -1; 67 oc->scale = -1;
63 oc->scale_filter = SCALE_FILTER_DEFAULT; 68 oc->scale_filter = SCALE_FILTER_DEFAULT;
@@ -65,6 +70,7 @@ struct output_config *new_output_config(const char *name) {
65 oc->subpixel = WL_OUTPUT_SUBPIXEL_UNKNOWN; 70 oc->subpixel = WL_OUTPUT_SUBPIXEL_UNKNOWN;
66 oc->max_render_time = -1; 71 oc->max_render_time = -1;
67 oc->adaptive_sync = -1; 72 oc->adaptive_sync = -1;
73 oc->render_bit_depth = RENDER_BIT_DEPTH_DEFAULT;
68 return oc; 74 return oc;
69} 75}
70 76
@@ -99,6 +105,9 @@ void merge_output_config(struct output_config *dst, struct output_config *src) {
99 if (src->custom_mode != -1) { 105 if (src->custom_mode != -1) {
100 dst->custom_mode = src->custom_mode; 106 dst->custom_mode = src->custom_mode;
101 } 107 }
108 if (src->drm_mode.type != (uint32_t) -1) {
109 memcpy(&dst->drm_mode, &src->drm_mode, sizeof(src->drm_mode));
110 }
102 if (src->transform != -1) { 111 if (src->transform != -1) {
103 dst->transform = src->transform; 112 dst->transform = src->transform;
104 } 113 }
@@ -108,6 +117,9 @@ void merge_output_config(struct output_config *dst, struct output_config *src) {
108 if (src->adaptive_sync != -1) { 117 if (src->adaptive_sync != -1) {
109 dst->adaptive_sync = src->adaptive_sync; 118 dst->adaptive_sync = src->adaptive_sync;
110 } 119 }
120 if (src->render_bit_depth != RENDER_BIT_DEPTH_DEFAULT) {
121 dst->render_bit_depth = src->render_bit_depth;
122 }
111 if (src->background) { 123 if (src->background) {
112 free(dst->background); 124 free(dst->background);
113 dst->background = strdup(src->background); 125 dst->background = strdup(src->background);
@@ -271,6 +283,18 @@ static void set_mode(struct wlr_output *output, int width, int height,
271 wlr_output_set_mode(output, best); 283 wlr_output_set_mode(output, best);
272} 284}
273 285
286static void set_modeline(struct wlr_output *output, drmModeModeInfo *drm_mode) {
287 if (!wlr_output_is_drm(output)) {
288 sway_log(SWAY_ERROR, "Modeline can only be set to DRM output");
289 return;
290 }
291 sway_log(SWAY_DEBUG, "Assigning custom modeline to %s", output->name);
292 struct wlr_output_mode *mode = wlr_drm_connector_add_mode(output, drm_mode);
293 if (mode) {
294 wlr_output_set_mode(output, mode);
295 }
296}
297
274/* Some manufacturers hardcode the aspect-ratio of the output in the physical 298/* Some manufacturers hardcode the aspect-ratio of the output in the physical
275 * size field. */ 299 * size field. */
276static bool phys_size_is_aspect_ratio(struct wlr_output *output) { 300static bool phys_size_is_aspect_ratio(struct wlr_output *output) {
@@ -334,9 +358,26 @@ static int compute_default_scale(struct wlr_output *output) {
334 return 2; 358 return 2;
335} 359}
336 360
361/* Lists of formats to try, in order, when a specific render bit depth has
362 * been asked for. The second to last format in each list should always
363 * be XRGB8888, as a reliable backup in case the others are not available;
364 * the last should be DRM_FORMAT_INVALID, to indicate the end of the list. */
365static const uint32_t *bit_depth_preferences[] = {
366 [RENDER_BIT_DEPTH_8] = (const uint32_t []){
367 DRM_FORMAT_XRGB8888,
368 DRM_FORMAT_INVALID,
369 },
370 [RENDER_BIT_DEPTH_10] = (const uint32_t []){
371 DRM_FORMAT_XRGB2101010,
372 DRM_FORMAT_XBGR2101010,
373 DRM_FORMAT_XRGB8888,
374 DRM_FORMAT_INVALID,
375 },
376};
377
337static void queue_output_config(struct output_config *oc, 378static void queue_output_config(struct output_config *oc,
338 struct sway_output *output) { 379 struct sway_output *output) {
339 if (output == root->noop_output) { 380 if (output == root->fallback_output) {
340 return; 381 return;
341 } 382 }
342 383
@@ -351,14 +392,36 @@ static void queue_output_config(struct output_config *oc,
351 sway_log(SWAY_DEBUG, "Turning on output %s", wlr_output->name); 392 sway_log(SWAY_DEBUG, "Turning on output %s", wlr_output->name);
352 wlr_output_enable(wlr_output, true); 393 wlr_output_enable(wlr_output, true);
353 394
354 if (oc && oc->width > 0 && oc->height > 0) { 395 if (oc && oc->drm_mode.type != 0 && oc->drm_mode.type != (uint32_t) -1) {
396 sway_log(SWAY_DEBUG, "Set %s modeline",
397 wlr_output->name);
398 set_modeline(wlr_output, &oc->drm_mode);
399 } else if (oc && oc->width > 0 && oc->height > 0) {
355 sway_log(SWAY_DEBUG, "Set %s mode to %dx%d (%f Hz)", 400 sway_log(SWAY_DEBUG, "Set %s mode to %dx%d (%f Hz)",
356 wlr_output->name, oc->width, oc->height, oc->refresh_rate); 401 wlr_output->name, oc->width, oc->height, oc->refresh_rate);
357 set_mode(wlr_output, oc->width, oc->height, 402 set_mode(wlr_output, oc->width, oc->height,
358 oc->refresh_rate, oc->custom_mode == 1); 403 oc->refresh_rate, oc->custom_mode == 1);
359 } else if (!wl_list_empty(&wlr_output->modes)) { 404 } else if (!wl_list_empty(&wlr_output->modes)) {
360 struct wlr_output_mode *mode = wlr_output_preferred_mode(wlr_output); 405 sway_log(SWAY_DEBUG, "Set preferred mode");
361 wlr_output_set_mode(wlr_output, mode); 406 struct wlr_output_mode *preferred_mode =
407 wlr_output_preferred_mode(wlr_output);
408 wlr_output_set_mode(wlr_output, preferred_mode);
409
410 if (!wlr_output_test(wlr_output)) {
411 sway_log(SWAY_DEBUG, "Preferred mode rejected, "
412 "falling back to another mode");
413 struct wlr_output_mode *mode;
414 wl_list_for_each(mode, &wlr_output->modes, link) {
415 if (mode == preferred_mode) {
416 continue;
417 }
418
419 wlr_output_set_mode(wlr_output, mode);
420 if (wlr_output_test(wlr_output)) {
421 break;
422 }
423 }
424 }
362 } 425 }
363 426
364 if (oc && (oc->subpixel != WL_OUTPUT_SUBPIXEL_UNKNOWN || config->reloading)) { 427 if (oc && (oc->subpixel != WL_OUTPUT_SUBPIXEL_UNKNOWN || config->reloading)) {
@@ -367,9 +430,16 @@ static void queue_output_config(struct output_config *oc,
367 wlr_output_set_subpixel(wlr_output, oc->subpixel); 430 wlr_output_set_subpixel(wlr_output, oc->subpixel);
368 } 431 }
369 432
433 enum wl_output_transform tr = WL_OUTPUT_TRANSFORM_NORMAL;
370 if (oc && oc->transform >= 0) { 434 if (oc && oc->transform >= 0) {
371 sway_log(SWAY_DEBUG, "Set %s transform to %d", oc->name, oc->transform); 435 tr = oc->transform;
372 wlr_output_set_transform(wlr_output, oc->transform); 436 } else if (wlr_output_is_drm(wlr_output)) {
437 tr = wlr_drm_connector_get_panel_orientation(wlr_output);
438 sway_log(SWAY_DEBUG, "Auto-detected output transform: %d", tr);
439 }
440 if (wlr_output->transform != tr) {
441 sway_log(SWAY_DEBUG, "Set %s transform to %d", oc->name, tr);
442 wlr_output_set_transform(wlr_output, tr);
373 } 443 }
374 444
375 // Apply the scale last before the commit, because the scale auto-detection 445 // Apply the scale last before the commit, because the scale auto-detection
@@ -391,10 +461,26 @@ static void queue_output_config(struct output_config *oc,
391 oc->adaptive_sync); 461 oc->adaptive_sync);
392 wlr_output_enable_adaptive_sync(wlr_output, oc->adaptive_sync == 1); 462 wlr_output_enable_adaptive_sync(wlr_output, oc->adaptive_sync == 1);
393 } 463 }
464
465 if (oc && oc->render_bit_depth != RENDER_BIT_DEPTH_DEFAULT) {
466 const uint32_t *fmts = bit_depth_preferences[oc->render_bit_depth];
467 assert(fmts);
468
469 for (size_t i = 0; fmts[i] != DRM_FORMAT_INVALID; i++) {
470 wlr_output_set_render_format(wlr_output, fmts[i]);
471 if (wlr_output_test(wlr_output)) {
472 break;
473 }
474
475 sway_log(SWAY_DEBUG, "Preferred output format 0x%08x "
476 "failed to work, falling back to next in "
477 "list, 0x%08x", fmts[i], fmts[i + 1]);
478 }
479 }
394} 480}
395 481
396bool apply_output_config(struct output_config *oc, struct sway_output *output) { 482bool apply_output_config(struct output_config *oc, struct sway_output *output) {
397 if (output == root->noop_output) { 483 if (output == root->fallback_output) {
398 return false; 484 return false;
399 } 485 }
400 486
@@ -462,12 +548,12 @@ bool apply_output_config(struct output_config *oc, struct sway_output *output) {
462 } 548 }
463 549
464 // Update output->{lx, ly, width, height} 550 // Update output->{lx, ly, width, height}
465 struct wlr_box *output_box = 551 struct wlr_box output_box;
466 wlr_output_layout_get_box(root->output_layout, wlr_output); 552 wlr_output_layout_get_box(root->output_layout, wlr_output, &output_box);
467 output->lx = output_box->x; 553 output->lx = output_box.x;
468 output->ly = output_box->y; 554 output->ly = output_box.y;
469 output->width = output_box->width; 555 output->width = output_box.width;
470 output->height = output_box->height; 556 output->height = output_box.height;
471 557
472 if (!output->enabled) { 558 if (!output->enabled) {
473 output_enable(output); 559 output_enable(output);
@@ -483,11 +569,13 @@ bool apply_output_config(struct output_config *oc, struct sway_output *output) {
483 // this output came online, and some config items (like map_to_output) are 569 // this output came online, and some config items (like map_to_output) are
484 // dependent on an output being present. 570 // dependent on an output being present.
485 input_manager_configure_all_inputs(); 571 input_manager_configure_all_inputs();
572 // Reconfigure the cursor images, since the scale may have changed.
573 input_manager_configure_xcursor();
486 return true; 574 return true;
487} 575}
488 576
489bool test_output_config(struct output_config *oc, struct sway_output *output) { 577bool test_output_config(struct output_config *oc, struct sway_output *output) {
490 if (output == root->noop_output) { 578 if (output == root->fallback_output) {
491 return false; 579 return false;
492 } 580 }
493 581
@@ -702,6 +790,8 @@ static bool _spawn_swaybg(char **command) {
702 sway_log_errno(SWAY_ERROR, "fork failed"); 790 sway_log_errno(SWAY_ERROR, "fork failed");
703 return false; 791 return false;
704 } else if (pid == 0) { 792 } else if (pid == 0) {
793 restore_nofile_limit();
794
705 pid = fork(); 795 pid = fork();
706 if (pid < 0) { 796 if (pid < 0) {
707 sway_log_errno(SWAY_ERROR, "fork failed"); 797 sway_log_errno(SWAY_ERROR, "fork failed");