aboutsummaryrefslogtreecommitdiff
path: root/sway/desktop
diff options
context:
space:
mode:
authorRyan Dwyer <ryandwyer1@gmail.com>2018-08-12 10:44:45 +1000
committerRyan Dwyer <ryandwyer1@gmail.com>2018-08-12 10:45:54 +1000
commit4b8e3a885be74c588291c51f798de80bd81a92db (patch)
tree54cd2d82e77158a3680da135c635cc108160afef /sway/desktop
parente7a7306063565f14052ed8b1d34ca19512a4fd66 (diff)
Don't commit multiple transactions at the same time
Diffstat (limited to 'sway/desktop')
-rw-r--r--sway/desktop/transaction.c80
1 files changed, 49 insertions, 31 deletions
diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c
index edbe34e5..a449ffaa 100644
--- a/sway/desktop/transaction.c
+++ b/sway/desktop/transaction.c
@@ -33,6 +33,7 @@ struct sway_transaction {
list_t *instructions; // struct sway_transaction_instruction *
size_t num_waiting;
size_t num_configures;
+ uint32_t con_ids; // Bitwise XOR of view container IDs
struct timespec create_time;
struct timespec commit_time;
};
@@ -212,29 +213,43 @@ static void transaction_apply(struct sway_transaction *transaction) {
}
}
+static void transaction_commit(struct sway_transaction *transaction);
+
static void transaction_progress_queue() {
- // Check if any transactions in the queue are in a partially ready state.
- // If so, we shouldn't progress any transactions, even ones which are fully
- // ready at the front of the queue, because the views in the ready
- // transactions might have committed past it to a transaction which isn't
- // yet ready.
- for (int i = 0; i < server.transactions->length; ++i) {
- struct sway_transaction *transaction = server.transactions->items[i];
- if (transaction->num_waiting != 0 &&
- transaction->num_waiting != transaction->num_configures) {
- return;
- }
+ if (!server.transactions->length) {
+ return;
}
- while (server.transactions->length) {
- struct sway_transaction *transaction = server.transactions->items[0];
- if (transaction->num_waiting) {
- return;
+ // There's only ever one committed transaction,
+ // and it's the first one in the queue.
+ struct sway_transaction *transaction = server.transactions->items[0];
+ if (transaction->num_waiting) {
+ return;
+ }
+ transaction_apply(transaction);
+ transaction_destroy(transaction);
+ list_del(server.transactions, 0);
+
+ if (!server.transactions->length) {
+ idle_inhibit_v1_check_active(server.idle_inhibit_manager_v1);
+ return;
+ }
+
+ // If there's a bunch of consecutive transactions which all apply to the
+ // same views, skip all except the last one.
+ while (server.transactions->length >= 2) {
+ struct sway_transaction *a = server.transactions->items[0];
+ struct sway_transaction *b = server.transactions->items[1];
+ if (a->con_ids == b->con_ids) {
+ list_del(server.transactions, 0);
+ transaction_destroy(a);
+ } else {
+ break;
}
- transaction_apply(transaction);
- transaction_destroy(transaction);
- list_del(server.transactions, 0);
}
- idle_inhibit_v1_check_active(server.idle_inhibit_manager_v1);
+
+ transaction = server.transactions->items[0];
+ transaction_commit(transaction);
+ transaction_progress_queue();
}
static int handle_timeout(void *data) {
@@ -288,6 +303,7 @@ static void transaction_commit(struct sway_transaction *transaction) {
instruction->state.view_width,
instruction->state.view_height);
++transaction->num_waiting;
+ transaction->con_ids ^= con->id;
// From here on we are rendering a saved buffer of the view, which
// means we can send a frame done event to make the client redraw it
@@ -305,17 +321,6 @@ static void transaction_commit(struct sway_transaction *transaction) {
if (server.debug_txn_timings) {
clock_gettime(CLOCK_MONOTONIC, &transaction->commit_time);
}
- if (server.transactions->length || transaction->num_waiting) {
- list_add(server.transactions, transaction);
- } else {
- // There are no other transactions in progress, and this one has nothing
- // to wait for, so we can skip the queue.
- wlr_log(WLR_DEBUG, "Transaction %p has nothing to wait for", transaction);
- transaction_apply(transaction);
- transaction_destroy(transaction);
- idle_inhibit_v1_check_active(server.idle_inhibit_manager_v1);
- return;
- }
if (transaction->num_waiting) {
// Set up a timer which the views must respond within
@@ -329,6 +334,9 @@ static void transaction_commit(struct sway_transaction *transaction) {
strerror(errno));
handle_timeout(transaction);
}
+ } 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
@@ -415,5 +423,15 @@ void transaction_commit_dirty(void) {
container->dirty = false;
}
server.dirty_containers->length = 0;
- transaction_commit(transaction);
+
+ list_add(server.transactions, transaction);
+
+ // There's only ever one committed transaction,
+ // and it's the first one in the queue.
+ if (server.transactions->length == 1) {
+ transaction_commit(transaction);
+ // Attempting to progress the queue here is useful
+ // if the transaction has nothing to wait for.
+ transaction_progress_queue();
+ }
}