diff options
author | Ryan Dwyer <ryandwyer1@gmail.com> | 2018-08-12 10:44:45 +1000 |
---|---|---|
committer | Ryan Dwyer <ryandwyer1@gmail.com> | 2018-08-12 10:45:54 +1000 |
commit | 4b8e3a885be74c588291c51f798de80bd81a92db (patch) | |
tree | 54cd2d82e77158a3680da135c635cc108160afef | |
parent | Don't progress transaction queue if any are partially complete (diff) | |
download | sway-4b8e3a885be74c588291c51f798de80bd81a92db.tar.gz sway-4b8e3a885be74c588291c51f798de80bd81a92db.tar.zst sway-4b8e3a885be74c588291c51f798de80bd81a92db.zip |
Don't commit multiple transactions at the same time
-rw-r--r-- | sway/desktop/transaction.c | 80 |
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 | ||
216 | static void transaction_commit(struct sway_transaction *transaction); | ||
217 | |||
215 | static void transaction_progress_queue() { | 218 | static 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 | ||
240 | static int handle_timeout(void *data) { | 255 | static 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 | } |