mirror of
https://github.com/swaywm/sway.git
synced 2024-11-23 00:11:28 +00:00
Don't commit multiple transactions at the same time
This commit is contained in:
parent
e7a7306063
commit
4b8e3a885b
|
@ -33,6 +33,7 @@ struct sway_transaction {
|
||||||
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
|
||||||
struct timespec create_time;
|
struct timespec create_time;
|
||||||
struct timespec commit_time;
|
struct timespec commit_time;
|
||||||
};
|
};
|
||||||
|
@ -212,20 +213,14 @@ static void transaction_apply(struct sway_transaction *transaction) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void transaction_commit(struct sway_transaction *transaction);
|
||||||
|
|
||||||
static void transaction_progress_queue() {
|
static void transaction_progress_queue() {
|
||||||
// Check if any transactions in the queue are in a partially ready state.
|
if (!server.transactions->length) {
|
||||||
// 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;
|
return;
|
||||||
}
|
}
|
||||||
}
|
// There's only ever one committed transaction,
|
||||||
while (server.transactions->length) {
|
// and it's the first one in the queue.
|
||||||
struct sway_transaction *transaction = server.transactions->items[0];
|
struct sway_transaction *transaction = server.transactions->items[0];
|
||||||
if (transaction->num_waiting) {
|
if (transaction->num_waiting) {
|
||||||
return;
|
return;
|
||||||
|
@ -233,8 +228,28 @@ static void transaction_progress_queue() {
|
||||||
transaction_apply(transaction);
|
transaction_apply(transaction);
|
||||||
transaction_destroy(transaction);
|
transaction_destroy(transaction);
|
||||||
list_del(server.transactions, 0);
|
list_del(server.transactions, 0);
|
||||||
}
|
|
||||||
|
if (!server.transactions->length) {
|
||||||
idle_inhibit_v1_check_active(server.idle_inhibit_manager_v1);
|
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 = server.transactions->items[0];
|
||||||
|
transaction_commit(transaction);
|
||||||
|
transaction_progress_queue();
|
||||||
}
|
}
|
||||||
|
|
||||||
static int handle_timeout(void *data) {
|
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_width,
|
||||||
instruction->state.view_height);
|
instruction->state.view_height);
|
||||||
++transaction->num_waiting;
|
++transaction->num_waiting;
|
||||||
|
transaction->con_ids ^= con->id;
|
||||||
|
|
||||||
// From here on we are rendering a saved buffer of the view, which
|
// 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
|
// 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) {
|
if (server.debug_txn_timings) {
|
||||||
clock_gettime(CLOCK_MONOTONIC, &transaction->commit_time);
|
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) {
|
if (transaction->num_waiting) {
|
||||||
// Set up a timer which the views must respond within
|
// Set up a timer which the views must respond within
|
||||||
|
@ -329,6 +334,9 @@ static void transaction_commit(struct sway_transaction *transaction) {
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
handle_timeout(transaction);
|
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
|
// 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;
|
container->dirty = false;
|
||||||
}
|
}
|
||||||
server.dirty_containers->length = 0;
|
server.dirty_containers->length = 0;
|
||||||
|
|
||||||
|
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);
|
transaction_commit(transaction);
|
||||||
|
// Attempting to progress the queue here is useful
|
||||||
|
// if the transaction has nothing to wait for.
|
||||||
|
transaction_progress_queue();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue