diff options
-rw-r--r-- | include/sway/debug.h | 19 | ||||
-rw-r--r-- | include/sway/server.h | 3 | ||||
-rw-r--r-- | sway/debug-tree.c | 8 | ||||
-rw-r--r-- | sway/desktop/render.c | 26 | ||||
-rw-r--r-- | sway/desktop/transaction.c | 57 | ||||
-rw-r--r-- | sway/main.c | 20 | ||||
-rw-r--r-- | sway/server.c | 7 |
7 files changed, 63 insertions, 77 deletions
diff --git a/include/sway/debug.h b/include/sway/debug.h index 38d4eccd..5dcd9e00 100644 --- a/include/sway/debug.h +++ b/include/sway/debug.h | |||
@@ -1,15 +1,18 @@ | |||
1 | #ifndef SWAY_DEBUG_H | 1 | #ifndef SWAY_DEBUG_H |
2 | #define SWAY_DEBUG_H | 2 | #define SWAY_DEBUG_H |
3 | #include <stdbool.h> | ||
3 | 4 | ||
4 | // Tree | 5 | struct sway_debug { |
5 | extern bool enable_debug_tree; | 6 | bool highlight_damage; // Highlight regions of the screen being damaged |
6 | void update_debug_tree(); | 7 | bool noatomic; // Ignore atomic layout updates |
8 | bool nodamage; // Render the full output on each frame | ||
9 | bool render_tree; // Render the tree overlay | ||
10 | bool txn_timings; // Log verbose messages about transactions | ||
11 | bool txn_wait; // Always wait for the timeout before applying | ||
12 | }; | ||
7 | 13 | ||
8 | // Damage | 14 | extern struct sway_debug debug; |
9 | extern const char *damage_debug; | ||
10 | 15 | ||
11 | // Transactions | 16 | void update_debug_tree(); |
12 | extern int txn_timeout_ms; | ||
13 | extern bool txn_debug; | ||
14 | 17 | ||
15 | #endif | 18 | #endif |
diff --git a/include/sway/server.h b/include/sway/server.h index b93584b6..1e20f2c8 100644 --- a/include/sway/server.h +++ b/include/sway/server.h | |||
@@ -54,8 +54,7 @@ struct sway_server { | |||
54 | struct wl_listener server_decoration; | 54 | struct wl_listener server_decoration; |
55 | struct wl_list decorations; // sway_server_decoration::link | 55 | struct wl_list decorations; // sway_server_decoration::link |
56 | 56 | ||
57 | bool debug_txn_timings; | 57 | size_t txn_timeout_ms; |
58 | |||
59 | list_t *transactions; | 58 | list_t *transactions; |
60 | list_t *dirty_containers; | 59 | list_t *dirty_containers; |
61 | }; | 60 | }; |
diff --git a/sway/debug-tree.c b/sway/debug-tree.c index f3465afe..b47a403b 100644 --- a/sway/debug-tree.c +++ b/sway/debug-tree.c | |||
@@ -3,8 +3,10 @@ | |||
3 | #include <wlr/render/wlr_texture.h> | 3 | #include <wlr/render/wlr_texture.h> |
4 | #include <wlr/util/log.h> | 4 | #include <wlr/util/log.h> |
5 | #include "config.h" | 5 | #include "config.h" |
6 | #include "sway/debug.h" | ||
6 | #include "sway/input/input-manager.h" | 7 | #include "sway/input/input-manager.h" |
7 | #include "sway/input/seat.h" | 8 | #include "sway/input/seat.h" |
9 | #include "sway/output.h" | ||
8 | #include "sway/server.h" | 10 | #include "sway/server.h" |
9 | #include "sway/tree/container.h" | 11 | #include "sway/tree/container.h" |
10 | #include "sway/tree/layout.h" | 12 | #include "sway/tree/layout.h" |
@@ -12,6 +14,8 @@ | |||
12 | #include "config.h" | 14 | #include "config.h" |
13 | #include "pango.h" | 15 | #include "pango.h" |
14 | 16 | ||
17 | struct sway_debug debug; | ||
18 | |||
15 | static const char *layout_to_str(enum sway_container_layout layout) { | 19 | static const char *layout_to_str(enum sway_container_layout layout) { |
16 | switch (layout) { | 20 | switch (layout) { |
17 | case L_HORIZ: | 21 | case L_HORIZ: |
@@ -69,10 +73,8 @@ static int draw_container(cairo_t *cairo, struct sway_container *container, | |||
69 | return height; | 73 | return height; |
70 | } | 74 | } |
71 | 75 | ||
72 | bool enable_debug_tree = false; | ||
73 | |||
74 | void update_debug_tree() { | 76 | void update_debug_tree() { |
75 | if (!enable_debug_tree) { | 77 | if (!debug.render_tree) { |
76 | return; | 78 | return; |
77 | } | 79 | } |
78 | 80 | ||
diff --git a/sway/desktop/render.c b/sway/desktop/render.c index 7c48d0d2..8fc642a6 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c | |||
@@ -816,8 +816,6 @@ static void render_floating(struct sway_output *soutput, | |||
816 | } | 816 | } |
817 | } | 817 | } |
818 | 818 | ||
819 | const char *damage_debug = NULL; | ||
820 | |||
821 | void output_render(struct sway_output *output, struct timespec *when, | 819 | void output_render(struct sway_output *output, struct timespec *when, |
822 | pixman_region32_t *damage) { | 820 | pixman_region32_t *damage) { |
823 | struct wlr_output *wlr_output = output->wlr_output; | 821 | struct wlr_output *wlr_output = output->wlr_output; |
@@ -831,21 +829,17 @@ void output_render(struct sway_output *output, struct timespec *when, | |||
831 | 829 | ||
832 | wlr_renderer_begin(renderer, wlr_output->width, wlr_output->height); | 830 | wlr_renderer_begin(renderer, wlr_output->width, wlr_output->height); |
833 | 831 | ||
834 | bool damage_whole_before_swap = false; | ||
835 | if (!pixman_region32_not_empty(damage)) { | 832 | if (!pixman_region32_not_empty(damage)) { |
836 | // Output isn't damaged but needs buffer swap | 833 | // Output isn't damaged but needs buffer swap |
837 | goto renderer_end; | 834 | goto renderer_end; |
838 | } | 835 | } |
839 | 836 | ||
840 | if (damage_debug != NULL) { | 837 | if (debug.highlight_damage) { |
841 | if (strcmp(damage_debug, "highlight") == 0) { | 838 | wlr_renderer_clear(renderer, (float[]){1, 1, 0, 1}); |
842 | wlr_renderer_clear(renderer, (float[]){1, 1, 0, 1}); | 839 | } else if (debug.nodamage) { |
843 | damage_whole_before_swap = true; | 840 | int width, height; |
844 | } else if (strcmp(damage_debug, "rerender") == 0) { | 841 | wlr_output_transformed_resolution(wlr_output, &width, &height); |
845 | int width, height; | 842 | pixman_region32_union_rect(damage, damage, 0, 0, width, height); |
846 | wlr_output_transformed_resolution(wlr_output, &width, &height); | ||
847 | pixman_region32_union_rect(damage, damage, 0, 0, width, height); | ||
848 | } | ||
849 | } | 843 | } |
850 | 844 | ||
851 | struct sway_container *workspace = output_get_active_workspace(output); | 845 | struct sway_container *workspace = output_get_active_workspace(output); |
@@ -919,12 +913,12 @@ render_overlay: | |||
919 | render_drag_icons(output, damage, &root_container.sway_root->drag_icons); | 913 | render_drag_icons(output, damage, &root_container.sway_root->drag_icons); |
920 | 914 | ||
921 | renderer_end: | 915 | renderer_end: |
922 | if (root_container.sway_root->debug_tree) { | 916 | if (debug.render_tree) { |
917 | wlr_renderer_scissor(renderer, NULL); | ||
923 | wlr_render_texture(renderer, root_container.sway_root->debug_tree, | 918 | wlr_render_texture(renderer, root_container.sway_root->debug_tree, |
924 | wlr_output->transform_matrix, 0, 0, 1); | 919 | wlr_output->transform_matrix, 0, 40, 1); |
925 | } | 920 | } |
926 | 921 | if (debug.highlight_damage) { | |
927 | if (damage_whole_before_swap || root_container.sway_root->debug_tree) { | ||
928 | int width, height; | 922 | int width, height; |
929 | wlr_output_transformed_resolution(wlr_output, &width, &height); | 923 | wlr_output_transformed_resolution(wlr_output, &width, &height); |
930 | pixman_region32_union_rect(damage, damage, 0, 0, width, height); | 924 | pixman_region32_union_rect(damage, damage, 0, 0, width, height); |
diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c index c300558a..219f5362 100644 --- a/sway/desktop/transaction.c +++ b/sway/desktop/transaction.c | |||
@@ -1,5 +1,6 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | 1 | #define _POSIX_C_SOURCE 200809L |
2 | #include <errno.h> | 2 | #include <errno.h> |
3 | #include <limits.h> | ||
3 | #include <stdbool.h> | 4 | #include <stdbool.h> |
4 | #include <stdlib.h> | 5 | #include <stdlib.h> |
5 | #include <string.h> | 6 | #include <string.h> |
@@ -16,26 +17,12 @@ | |||
16 | #include "list.h" | 17 | #include "list.h" |
17 | #include "log.h" | 18 | #include "log.h" |
18 | 19 | ||
19 | /** | ||
20 | * How long we should wait for views to respond to the configure before giving | ||
21 | * up and applying the transaction anyway. | ||
22 | */ | ||
23 | int txn_timeout_ms = 200; | ||
24 | |||
25 | /** | ||
26 | * If enabled, sway will always wait for the transaction timeout before | ||
27 | * applying it, rather than applying it when the views are ready. This allows us | ||
28 | * to observe the rendered state while a transaction is in progress. | ||
29 | */ | ||
30 | bool txn_debug = false; | ||
31 | |||
32 | struct sway_transaction { | 20 | struct sway_transaction { |
33 | struct wl_event_source *timer; | 21 | struct wl_event_source *timer; |
34 | list_t *instructions; // struct sway_transaction_instruction * | 22 | list_t *instructions; // struct sway_transaction_instruction * |
35 | size_t num_waiting; | 23 | size_t num_waiting; |
36 | size_t num_configures; | 24 | size_t num_configures; |
37 | uint32_t con_ids; // Bitwise XOR of view container IDs | 25 | uint32_t con_ids; // Bitwise XOR of view container IDs |
38 | struct timespec create_time; | ||
39 | struct timespec commit_time; | 26 | struct timespec commit_time; |
40 | }; | 27 | }; |
41 | 28 | ||
@@ -53,9 +40,6 @@ static struct sway_transaction *transaction_create() { | |||
53 | return NULL; | 40 | return NULL; |
54 | } | 41 | } |
55 | transaction->instructions = create_list(); | 42 | transaction->instructions = create_list(); |
56 | if (server.debug_txn_timings) { | ||
57 | clock_gettime(CLOCK_MONOTONIC, &transaction->create_time); | ||
58 | } | ||
59 | return transaction; | 43 | return transaction; |
60 | } | 44 | } |
61 | 45 | ||
@@ -149,19 +133,14 @@ static void transaction_add_container(struct sway_transaction *transaction, | |||
149 | */ | 133 | */ |
150 | static void transaction_apply(struct sway_transaction *transaction) { | 134 | static void transaction_apply(struct sway_transaction *transaction) { |
151 | wlr_log(WLR_DEBUG, "Applying transaction %p", transaction); | 135 | wlr_log(WLR_DEBUG, "Applying transaction %p", transaction); |
152 | if (server.debug_txn_timings) { | 136 | if (debug.txn_timings) { |
153 | struct timespec now; | 137 | struct timespec now; |
154 | clock_gettime(CLOCK_MONOTONIC, &now); | 138 | clock_gettime(CLOCK_MONOTONIC, &now); |
155 | struct timespec *create = &transaction->create_time; | ||
156 | struct timespec *commit = &transaction->commit_time; | 139 | struct timespec *commit = &transaction->commit_time; |
157 | float ms_arranging = (commit->tv_sec - create->tv_sec) * 1000 + | 140 | float ms = (now.tv_sec - commit->tv_sec) * 1000 + |
158 | (commit->tv_nsec - create->tv_nsec) / 1000000.0; | ||
159 | float ms_waiting = (now.tv_sec - commit->tv_sec) * 1000 + | ||
160 | (now.tv_nsec - commit->tv_nsec) / 1000000.0; | 141 | (now.tv_nsec - commit->tv_nsec) / 1000000.0; |
161 | float ms_total = ms_arranging + ms_waiting; | 142 | wlr_log(WLR_DEBUG, "Transaction %p: %.1fms waiting " |
162 | wlr_log(WLR_DEBUG, "Transaction %p: %.1fms arranging, %.1fms waiting, " | 143 | "(%.1f frames if 60Hz)", transaction, ms, ms / (1000.0f / 60)); |
163 | "%.1fms total (%.1f frames if 60Hz)", transaction, | ||
164 | ms_arranging, ms_waiting, ms_total, ms_total / (1000.0f / 60)); | ||
165 | } | 144 | } |
166 | 145 | ||
167 | // Apply the instruction state to the container's current state | 146 | // Apply the instruction state to the container's current state |
@@ -310,25 +289,30 @@ static void transaction_commit(struct sway_transaction *transaction) { | |||
310 | con->instruction = instruction; | 289 | con->instruction = instruction; |
311 | } | 290 | } |
312 | transaction->num_configures = transaction->num_waiting; | 291 | transaction->num_configures = transaction->num_waiting; |
313 | if (server.debug_txn_timings) { | 292 | if (debug.txn_timings) { |
314 | clock_gettime(CLOCK_MONOTONIC, &transaction->commit_time); | 293 | clock_gettime(CLOCK_MONOTONIC, &transaction->commit_time); |
315 | } | 294 | } |
295 | if (debug.noatomic) { | ||
296 | transaction->num_waiting = 0; | ||
297 | } else if (debug.txn_wait) { | ||
298 | // Force the transaction to time out even if all views are ready. | ||
299 | // We do this by inflating the waiting counter. | ||
300 | transaction->num_waiting += 1000000; | ||
301 | } | ||
316 | 302 | ||
317 | if (transaction->num_waiting) { | 303 | if (transaction->num_waiting) { |
318 | // Set up a timer which the views must respond within | 304 | // Set up a timer which the views must respond within |
319 | transaction->timer = wl_event_loop_add_timer(server.wl_event_loop, | 305 | transaction->timer = wl_event_loop_add_timer(server.wl_event_loop, |
320 | handle_timeout, transaction); | 306 | handle_timeout, transaction); |
321 | if (transaction->timer) { | 307 | if (transaction->timer) { |
322 | wl_event_source_timer_update(transaction->timer, txn_timeout_ms); | 308 | wl_event_source_timer_update(transaction->timer, |
309 | server.txn_timeout_ms); | ||
323 | } else { | 310 | } else { |
324 | wlr_log(WLR_ERROR, "Unable to create transaction timer (%s). " | 311 | wlr_log(WLR_ERROR, "Unable to create transaction timer (%s). " |
325 | "Some imperfect frames might be rendered.", | 312 | "Some imperfect frames might be rendered.", |
326 | strerror(errno)); | 313 | strerror(errno)); |
327 | handle_timeout(transaction); | 314 | transaction->num_waiting = 0; |
328 | } | 315 | } |
329 | } else { | ||
330 | wlr_log(WLR_DEBUG, | ||
331 | "Transaction %p has nothing to wait for", transaction); | ||
332 | } | 316 | } |
333 | 317 | ||
334 | // The debug tree shows the pending/live tree. Here is a good place to | 318 | // The debug tree shows the pending/live tree. Here is a good place to |
@@ -341,7 +325,7 @@ static void set_instruction_ready( | |||
341 | struct sway_transaction_instruction *instruction) { | 325 | struct sway_transaction_instruction *instruction) { |
342 | struct sway_transaction *transaction = instruction->transaction; | 326 | struct sway_transaction *transaction = instruction->transaction; |
343 | 327 | ||
344 | if (server.debug_txn_timings) { | 328 | if (debug.txn_timings) { |
345 | struct timespec now; | 329 | struct timespec now; |
346 | clock_gettime(CLOCK_MONOTONIC, &now); | 330 | clock_gettime(CLOCK_MONOTONIC, &now); |
347 | struct timespec *start = &transaction->commit_time; | 331 | struct timespec *start = &transaction->commit_time; |
@@ -352,15 +336,12 @@ static void set_instruction_ready( | |||
352 | transaction->num_configures - transaction->num_waiting + 1, | 336 | transaction->num_configures - transaction->num_waiting + 1, |
353 | transaction->num_configures, ms, | 337 | transaction->num_configures, ms, |
354 | instruction->container->name); | 338 | instruction->container->name); |
355 | |||
356 | } | 339 | } |
357 | 340 | ||
358 | // If the transaction has timed out then its num_waiting will be 0 already. | 341 | // If the transaction has timed out then its num_waiting will be 0 already. |
359 | if (transaction->num_waiting > 0 && --transaction->num_waiting == 0) { | 342 | if (transaction->num_waiting > 0 && --transaction->num_waiting == 0) { |
360 | if (!txn_debug) { | 343 | wlr_log(WLR_DEBUG, "Transaction %p is ready", transaction); |
361 | wlr_log(WLR_DEBUG, "Transaction %p is ready", transaction); | 344 | wl_event_source_timer_update(transaction->timer, 0); |
362 | wl_event_source_timer_update(transaction->timer, 0); | ||
363 | } | ||
364 | } | 345 | } |
365 | 346 | ||
366 | instruction->container->instruction = NULL; | 347 | instruction->container->instruction = NULL; |
diff --git a/sway/main.c b/sway/main.c index 54f48340..7a1afd4c 100644 --- a/sway/main.c +++ b/sway/main.c | |||
@@ -235,14 +235,20 @@ static void drop_permissions(bool keep_caps) { | |||
235 | } | 235 | } |
236 | 236 | ||
237 | void enable_debug_flag(const char *flag) { | 237 | void enable_debug_flag(const char *flag) { |
238 | if (strcmp(flag, "render-tree") == 0) { | 238 | if (strcmp(flag, "highlight-damage") == 0) { |
239 | enable_debug_tree = true; | 239 | debug.highlight_damage = true; |
240 | } else if (strncmp(flag, "damage=", 7) == 0) { | 240 | } else if (strcmp(flag, "noatomic") == 0) { |
241 | damage_debug = &flag[7]; | 241 | debug.noatomic = true; |
242 | } else if (strcmp(flag, "txn-debug") == 0) { | 242 | } else if (strcmp(flag, "nodamage") == 0) { |
243 | txn_debug = true; | 243 | debug.nodamage = true; |
244 | } else if (strcmp(flag, "render-tree") == 0) { | ||
245 | debug.render_tree = true; | ||
246 | } else if (strcmp(flag, "txn-wait") == 0) { | ||
247 | debug.txn_wait = true; | ||
248 | } else if (strcmp(flag, "txn-timings") == 0) { | ||
249 | debug.txn_timings = true; | ||
244 | } else if (strncmp(flag, "txn-timeout=", 12) == 0) { | 250 | } else if (strncmp(flag, "txn-timeout=", 12) == 0) { |
245 | txn_timeout_ms = atoi(&flag[12]); | 251 | server.txn_timeout_ms = atoi(&flag[12]); |
246 | } | 252 | } |
247 | } | 253 | } |
248 | 254 | ||
diff --git a/sway/server.c b/sway/server.c index e8dc63be..00acaa01 100644 --- a/sway/server.c +++ b/sway/server.c | |||
@@ -128,10 +128,11 @@ bool server_init(struct sway_server *server) { | |||
128 | return false; | 128 | return false; |
129 | } | 129 | } |
130 | 130 | ||
131 | const char *debug = getenv("SWAY_DEBUG"); | 131 | // This may have been set already via -Dtxn-timeout |
132 | if (debug != NULL && strcmp(debug, "txn_timings") == 0) { | 132 | if (!server->txn_timeout_ms) { |
133 | server->debug_txn_timings = true; | 133 | server->txn_timeout_ms = 200; |
134 | } | 134 | } |
135 | |||
135 | server->dirty_containers = create_list(); | 136 | server->dirty_containers = create_list(); |
136 | server->transactions = create_list(); | 137 | server->transactions = create_list(); |
137 | 138 | ||