Standardise debug variables

This makes all debug options stored in a single struct rather than in
various places, changes/fixes the behaviour of existing options, and
introduces some new options.

* Fixes damage issues with `-Drender-tree` texture (by removing scissor)
* Offsets the render tree overlay's `y` position for those who have
swaybar at the top
* Replaces `-Ddamage=rerender` with `-Dnodamage`
* Replaces `-Ddamage=highlight` with `-Dhighlight-damage`
* Replaces `-Dtxn-debug` with `-Dtxn-wait`
* Introduces `-Dnoatomic`
* Removes the `create_time` and `ms_arranging` figures from transactions
and the log message. Transactions are created after arranging and the
create time is of no significance.
* Fixes `-Dtxn-debug` (now `-Dtxn-wait`) not working.
This commit is contained in:
Ryan Dwyer 2018-08-18 16:58:50 +10:00
parent 389d159c81
commit 8d1dd03823
7 changed files with 64 additions and 78 deletions

View file

@ -1,15 +1,18 @@
#ifndef SWAY_DEBUG_H #ifndef SWAY_DEBUG_H
#define SWAY_DEBUG_H #define SWAY_DEBUG_H
#include <stdbool.h>
struct sway_debug {
bool highlight_damage; // Highlight regions of the screen being damaged
bool noatomic; // Ignore atomic layout updates
bool nodamage; // Render the full output on each frame
bool render_tree; // Render the tree overlay
bool txn_timings; // Log verbose messages about transactions
bool txn_wait; // Always wait for the timeout before applying
};
extern struct sway_debug debug;
// Tree
extern bool enable_debug_tree;
void update_debug_tree(); void update_debug_tree();
// Damage
extern const char *damage_debug;
// Transactions
extern int txn_timeout_ms;
extern bool txn_debug;
#endif #endif

View file

@ -54,8 +54,7 @@ struct sway_server {
struct wl_listener server_decoration; struct wl_listener server_decoration;
struct wl_list decorations; // sway_server_decoration::link struct wl_list decorations; // sway_server_decoration::link
bool debug_txn_timings; size_t txn_timeout_ms;
list_t *transactions; list_t *transactions;
list_t *dirty_containers; list_t *dirty_containers;
}; };

View file

@ -3,8 +3,10 @@
#include <wlr/render/wlr_texture.h> #include <wlr/render/wlr_texture.h>
#include <wlr/util/log.h> #include <wlr/util/log.h>
#include "config.h" #include "config.h"
#include "sway/debug.h"
#include "sway/input/input-manager.h" #include "sway/input/input-manager.h"
#include "sway/input/seat.h" #include "sway/input/seat.h"
#include "sway/output.h"
#include "sway/server.h" #include "sway/server.h"
#include "sway/tree/container.h" #include "sway/tree/container.h"
#include "sway/tree/layout.h" #include "sway/tree/layout.h"
@ -12,6 +14,8 @@
#include "config.h" #include "config.h"
#include "pango.h" #include "pango.h"
struct sway_debug debug;
static const char *layout_to_str(enum sway_container_layout layout) { static const char *layout_to_str(enum sway_container_layout layout) {
switch (layout) { switch (layout) {
case L_HORIZ: case L_HORIZ:
@ -69,10 +73,8 @@ static int draw_container(cairo_t *cairo, struct sway_container *container,
return height; return height;
} }
bool enable_debug_tree = false;
void update_debug_tree() { void update_debug_tree() {
if (!enable_debug_tree) { if (!debug.render_tree) {
return; return;
} }

View file

@ -816,8 +816,6 @@ static void render_floating(struct sway_output *soutput,
} }
} }
const char *damage_debug = NULL;
void output_render(struct sway_output *output, struct timespec *when, void output_render(struct sway_output *output, struct timespec *when,
pixman_region32_t *damage) { pixman_region32_t *damage) {
struct wlr_output *wlr_output = output->wlr_output; struct wlr_output *wlr_output = output->wlr_output;
@ -831,21 +829,17 @@ void output_render(struct sway_output *output, struct timespec *when,
wlr_renderer_begin(renderer, wlr_output->width, wlr_output->height); wlr_renderer_begin(renderer, wlr_output->width, wlr_output->height);
bool damage_whole_before_swap = false;
if (!pixman_region32_not_empty(damage)) { if (!pixman_region32_not_empty(damage)) {
// Output isn't damaged but needs buffer swap // Output isn't damaged but needs buffer swap
goto renderer_end; goto renderer_end;
} }
if (damage_debug != NULL) { if (debug.highlight_damage) {
if (strcmp(damage_debug, "highlight") == 0) { wlr_renderer_clear(renderer, (float[]){1, 1, 0, 1});
wlr_renderer_clear(renderer, (float[]){1, 1, 0, 1}); } else if (debug.nodamage) {
damage_whole_before_swap = true; int width, height;
} else if (strcmp(damage_debug, "rerender") == 0) { wlr_output_transformed_resolution(wlr_output, &width, &height);
int width, height; pixman_region32_union_rect(damage, damage, 0, 0, width, height);
wlr_output_transformed_resolution(wlr_output, &width, &height);
pixman_region32_union_rect(damage, damage, 0, 0, width, height);
}
} }
struct sway_container *workspace = output_get_active_workspace(output); struct sway_container *workspace = output_get_active_workspace(output);
@ -919,12 +913,12 @@ render_overlay:
render_drag_icons(output, damage, &root_container.sway_root->drag_icons); render_drag_icons(output, damage, &root_container.sway_root->drag_icons);
renderer_end: renderer_end:
if (root_container.sway_root->debug_tree) { if (debug.render_tree) {
wlr_renderer_scissor(renderer, NULL);
wlr_render_texture(renderer, root_container.sway_root->debug_tree, wlr_render_texture(renderer, root_container.sway_root->debug_tree,
wlr_output->transform_matrix, 0, 0, 1); wlr_output->transform_matrix, 0, 40, 1);
} }
if (debug.highlight_damage) {
if (damage_whole_before_swap || root_container.sway_root->debug_tree) {
int width, height; int width, height;
wlr_output_transformed_resolution(wlr_output, &width, &height); wlr_output_transformed_resolution(wlr_output, &width, &height);
pixman_region32_union_rect(damage, damage, 0, 0, width, height); pixman_region32_union_rect(damage, damage, 0, 0, width, height);

View file

@ -1,5 +1,6 @@
#define _POSIX_C_SOURCE 200809L #define _POSIX_C_SOURCE 200809L
#include <errno.h> #include <errno.h>
#include <limits.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -16,26 +17,12 @@
#include "list.h" #include "list.h"
#include "log.h" #include "log.h"
/**
* How long we should wait for views to respond to the configure before giving
* up and applying the transaction anyway.
*/
int txn_timeout_ms = 200;
/**
* If enabled, sway will always wait for the transaction timeout before
* applying it, rather than applying it when the views are ready. This allows us
* to observe the rendered state while a transaction is in progress.
*/
bool txn_debug = false;
struct sway_transaction { struct sway_transaction {
struct wl_event_source *timer; struct wl_event_source *timer;
list_t *instructions; // struct sway_transaction_instruction * list_t *instructions; // struct sway_transaction_instruction *
size_t num_waiting; size_t num_waiting;
size_t num_configures; size_t num_configures;
uint32_t con_ids; // Bitwise XOR of view container IDs uint32_t con_ids; // Bitwise XOR of view container IDs
struct timespec create_time;
struct timespec commit_time; struct timespec commit_time;
}; };
@ -53,9 +40,6 @@ static struct sway_transaction *transaction_create() {
return NULL; return NULL;
} }
transaction->instructions = create_list(); transaction->instructions = create_list();
if (server.debug_txn_timings) {
clock_gettime(CLOCK_MONOTONIC, &transaction->create_time);
}
return transaction; return transaction;
} }
@ -149,19 +133,14 @@ static void transaction_add_container(struct sway_transaction *transaction,
*/ */
static void transaction_apply(struct sway_transaction *transaction) { static void transaction_apply(struct sway_transaction *transaction) {
wlr_log(WLR_DEBUG, "Applying transaction %p", transaction); wlr_log(WLR_DEBUG, "Applying transaction %p", transaction);
if (server.debug_txn_timings) { if (debug.txn_timings) {
struct timespec now; struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now); clock_gettime(CLOCK_MONOTONIC, &now);
struct timespec *create = &transaction->create_time;
struct timespec *commit = &transaction->commit_time; struct timespec *commit = &transaction->commit_time;
float ms_arranging = (commit->tv_sec - create->tv_sec) * 1000 + float ms = (now.tv_sec - commit->tv_sec) * 1000 +
(commit->tv_nsec - create->tv_nsec) / 1000000.0;
float ms_waiting = (now.tv_sec - commit->tv_sec) * 1000 +
(now.tv_nsec - commit->tv_nsec) / 1000000.0; (now.tv_nsec - commit->tv_nsec) / 1000000.0;
float ms_total = ms_arranging + ms_waiting; wlr_log(WLR_DEBUG, "Transaction %p: %.1fms waiting "
wlr_log(WLR_DEBUG, "Transaction %p: %.1fms arranging, %.1fms waiting, " "(%.1f frames if 60Hz)", transaction, ms, ms / (1000.0f / 60));
"%.1fms total (%.1f frames if 60Hz)", transaction,
ms_arranging, ms_waiting, ms_total, ms_total / (1000.0f / 60));
} }
// Apply the instruction state to the container's current state // Apply the instruction state to the container's current state
@ -310,25 +289,30 @@ static void transaction_commit(struct sway_transaction *transaction) {
con->instruction = instruction; con->instruction = instruction;
} }
transaction->num_configures = transaction->num_waiting; transaction->num_configures = transaction->num_waiting;
if (server.debug_txn_timings) { if (debug.txn_timings) {
clock_gettime(CLOCK_MONOTONIC, &transaction->commit_time); clock_gettime(CLOCK_MONOTONIC, &transaction->commit_time);
} }
if (debug.noatomic) {
transaction->num_waiting = 0;
} else if (debug.txn_wait) {
// Force the transaction to time out even if all views are ready.
// We do this by inflating the waiting counter.
transaction->num_waiting += 1000000;
}
if (transaction->num_waiting) { if (transaction->num_waiting) {
// Set up a timer which the views must respond within // Set up a timer which the views must respond within
transaction->timer = wl_event_loop_add_timer(server.wl_event_loop, transaction->timer = wl_event_loop_add_timer(server.wl_event_loop,
handle_timeout, transaction); handle_timeout, transaction);
if (transaction->timer) { if (transaction->timer) {
wl_event_source_timer_update(transaction->timer, txn_timeout_ms); wl_event_source_timer_update(transaction->timer,
server.txn_timeout_ms);
} else { } else {
wlr_log(WLR_ERROR, "Unable to create transaction timer (%s). " wlr_log(WLR_ERROR, "Unable to create transaction timer (%s). "
"Some imperfect frames might be rendered.", "Some imperfect frames might be rendered.",
strerror(errno)); strerror(errno));
handle_timeout(transaction); transaction->num_waiting = 0;
} }
} else {
wlr_log(WLR_DEBUG,
"Transaction %p has nothing to wait for", transaction);
} }
// The debug tree shows the pending/live tree. Here is a good place to // The debug tree shows the pending/live tree. Here is a good place to
@ -341,7 +325,7 @@ static void set_instruction_ready(
struct sway_transaction_instruction *instruction) { struct sway_transaction_instruction *instruction) {
struct sway_transaction *transaction = instruction->transaction; struct sway_transaction *transaction = instruction->transaction;
if (server.debug_txn_timings) { if (debug.txn_timings) {
struct timespec now; struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now); clock_gettime(CLOCK_MONOTONIC, &now);
struct timespec *start = &transaction->commit_time; struct timespec *start = &transaction->commit_time;
@ -352,15 +336,12 @@ static void set_instruction_ready(
transaction->num_configures - transaction->num_waiting + 1, transaction->num_configures - transaction->num_waiting + 1,
transaction->num_configures, ms, transaction->num_configures, ms,
instruction->container->name); instruction->container->name);
} }
// If the transaction has timed out then its num_waiting will be 0 already. // If the transaction has timed out then its num_waiting will be 0 already.
if (transaction->num_waiting > 0 && --transaction->num_waiting == 0) { if (transaction->num_waiting > 0 && --transaction->num_waiting == 0) {
if (!txn_debug) { wlr_log(WLR_DEBUG, "Transaction %p is ready", transaction);
wlr_log(WLR_DEBUG, "Transaction %p is ready", transaction); wl_event_source_timer_update(transaction->timer, 0);
wl_event_source_timer_update(transaction->timer, 0);
}
} }
instruction->container->instruction = NULL; instruction->container->instruction = NULL;

View file

@ -235,14 +235,20 @@ static void drop_permissions(bool keep_caps) {
} }
void enable_debug_flag(const char *flag) { void enable_debug_flag(const char *flag) {
if (strcmp(flag, "render-tree") == 0) { if (strcmp(flag, "highlight-damage") == 0) {
enable_debug_tree = true; debug.highlight_damage = true;
} else if (strncmp(flag, "damage=", 7) == 0) { } else if (strcmp(flag, "noatomic") == 0) {
damage_debug = &flag[7]; debug.noatomic = true;
} else if (strcmp(flag, "txn-debug") == 0) { } else if (strcmp(flag, "nodamage") == 0) {
txn_debug = true; debug.nodamage = true;
} else if (strcmp(flag, "render-tree") == 0) {
debug.render_tree = true;
} else if (strcmp(flag, "txn-wait") == 0) {
debug.txn_wait = true;
} else if (strcmp(flag, "txn-timings") == 0) {
debug.txn_timings = true;
} else if (strncmp(flag, "txn-timeout=", 12) == 0) { } else if (strncmp(flag, "txn-timeout=", 12) == 0) {
txn_timeout_ms = atoi(&flag[12]); server.txn_timeout_ms = atoi(&flag[12]);
} }
} }

View file

@ -128,10 +128,11 @@ bool server_init(struct sway_server *server) {
return false; return false;
} }
const char *debug = getenv("SWAY_DEBUG"); // This may have been set already via -Dtxn-timeout
if (debug != NULL && strcmp(debug, "txn_timings") == 0) { if (!server->txn_timeout_ms) {
server->debug_txn_timings = true; server->txn_timeout_ms = 200;
} }
server->dirty_containers = create_list(); server->dirty_containers = create_list();
server->transactions = create_list(); server->transactions = create_list();