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:
parent
389d159c81
commit
8d1dd03823
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
20
sway/main.c
20
sway/main.c
|
@ -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]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue