aboutsummaryrefslogtreecommitdiffstats
path: root/sway/desktop/transaction.c
diff options
context:
space:
mode:
authorLibravatar Ryan Dwyer <ryandwyer1@gmail.com>2018-08-12 10:44:45 +1000
committerLibravatar Ryan Dwyer <ryandwyer1@gmail.com>2018-08-12 10:45:54 +1000
commit4b8e3a885be74c588291c51f798de80bd81a92db (patch)
tree54cd2d82e77158a3680da135c635cc108160afef /sway/desktop/transaction.c
parentDon't progress transaction queue if any are partially complete (diff)
downloadsway-4b8e3a885be74c588291c51f798de80bd81a92db.tar.gz
sway-4b8e3a885be74c588291c51f798de80bd81a92db.tar.zst
sway-4b8e3a885be74c588291c51f798de80bd81a92db.zip
Don't commit multiple transactions at the same time
Diffstat (limited to 'sway/desktop/transaction.c')
-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 {
33 list_t *instructions; // struct sway_transaction_instruction * 33 list_t *instructions; // struct sway_transaction_instruction *
34 size_t num_waiting; 34 size_t num_waiting;
35 size_t num_configures; 35 size_t num_configures;
36 uint32_t con_ids; // Bitwise XOR of view container IDs
36 struct timespec create_time; 37 struct timespec create_time;
37 struct timespec commit_time; 38 struct timespec commit_time;
38}; 39};
@@ -212,29 +213,43 @@ static void transaction_apply(struct sway_transaction *transaction) {
212 } 213 }
213} 214}
214 215
216static void transaction_commit(struct sway_transaction *transaction);
217
215static void transaction_progress_queue() { 218static void transaction_progress_queue() {
216 // Check if any transactions in the queue are in a partially ready state. 219 if (!server.transactions->length) {
217 // If so, we shouldn't progress any transactions, even ones which are fully 220 return;
218 // ready at the front of the queue, because the views in the ready
219 // transactions might have committed past it to a transaction which isn't
220 // yet ready.
221 for (int i = 0; i < server.transactions->length; ++i) {
222 struct sway_transaction *transaction = server.transactions->items[i];
223 if (transaction->num_waiting != 0 &&
224 transaction->num_waiting != transaction->num_configures) {
225 return;
226 }
227 } 221 }
228 while (server.transactions->length) { 222 // There's only ever one committed transaction,
229 struct sway_transaction *transaction = server.transactions->items[0]; 223 // and it's the first one in the queue.
230 if (transaction->num_waiting) { 224 struct sway_transaction *transaction = server.transactions->items[0];
231 return; 225 if (transaction->num_waiting) {
226 return;
227 }
228 transaction_apply(transaction);
229 transaction_destroy(transaction);
230 list_del(server.transactions, 0);
231
232 if (!server.transactions->length) {
233 idle_inhibit_v1_check_active(server.idle_inhibit_manager_v1);
234 return;
235 }
236
237 // If there's a bunch of consecutive transactions which all apply to the
238 // same views, skip all except the last one.
239 while (server.transactions->length >= 2) {
240 struct sway_transaction *a = server.transactions->items[0];
241 struct sway_transaction *b = server.transactions->items[1];
242 if (a->con_ids == b->con_ids) {
243 list_del(server.transactions, 0);
244 transaction_destroy(a);
245 } else {
246 break;
232 } 247 }
233 transaction_apply(transaction);
234 transaction_destroy(transaction);
235 list_del(server.transactions, 0);
236 } 248 }
237 idle_inhibit_v1_check_active(server.idle_inhibit_manager_v1); 249
250 transaction = server.transactions->items[0];
251 transaction_commit(transaction);
252 transaction_progress_queue();
238} 253}
239 254
240static int handle_timeout(void *data) { 255static int handle_timeout(void *data) {
@@ -288,6 +303,7 @@ static void transaction_commit(struct sway_transaction *transaction) {
288 instruction->state.view_width, 303 instruction->state.view_width,
289 instruction->state.view_height); 304 instruction->state.view_height);
290 ++transaction->num_waiting; 305 ++transaction->num_waiting;
306 transaction->con_ids ^= con->id;
291 307
292 // From here on we are rendering a saved buffer of the view, which 308 // From here on we are rendering a saved buffer of the view, which
293 // means we can send a frame done event to make the client redraw it 309 // 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) {
305 if (server.debug_txn_timings) { 321 if (server.debug_txn_timings) {
306 clock_gettime(CLOCK_MONOTONIC, &transaction->commit_time); 322 clock_gettime(CLOCK_MONOTONIC, &transaction->commit_time);
307 } 323 }
308 if (server.transactions->length || transaction->num_waiting) {
309 list_add(server.transactions, transaction);
310 } else {
311 // There are no other transactions in progress, and this one has nothing
312 // to wait for, so we can skip the queue.
313 wlr_log(WLR_DEBUG, "Transaction %p has nothing to wait for", transaction);
314 transaction_apply(transaction);
315 transaction_destroy(transaction);
316 idle_inhibit_v1_check_active(server.idle_inhibit_manager_v1);
317 return;
318 }
319 324
320 if (transaction->num_waiting) { 325 if (transaction->num_waiting) {
321 // Set up a timer which the views must respond within 326 // Set up a timer which the views must respond within
@@ -329,6 +334,9 @@ static void transaction_commit(struct sway_transaction *transaction) {
329 strerror(errno)); 334 strerror(errno));
330 handle_timeout(transaction); 335 handle_timeout(transaction);
331 } 336 }
337 } else {
338 wlr_log(WLR_DEBUG,
339 "Transaction %p has nothing to wait for", transaction);
332 } 340 }
333 341
334 // The debug tree shows the pending/live tree. Here is a good place to 342 // The debug tree shows the pending/live tree. Here is a good place to
@@ -415,5 +423,15 @@ void transaction_commit_dirty(void) {
415 container->dirty = false; 423 container->dirty = false;
416 } 424 }
417 server.dirty_containers->length = 0; 425 server.dirty_containers->length = 0;
418 transaction_commit(transaction); 426
427 list_add(server.transactions, transaction);
428
429 // There's only ever one committed transaction,
430 // and it's the first one in the queue.
431 if (server.transactions->length == 1) {
432 transaction_commit(transaction);
433 // Attempting to progress the queue here is useful
434 // if the transaction has nothing to wait for.
435 transaction_progress_queue();
436 }
419} 437}