| OLD | NEW |
| 1 Sky's Run Loop | 1 Sky's Run Loop |
| 2 ============== | 2 ============== |
| 3 | 3 |
| 4 Sky has three task queues, named idle, paint, and nextPaint. |
| 5 |
| 6 When a task is run, it has a time budget, and if the time budget is |
| 7 exceeded, then a catchable DeadlineExceededException exception is |
| 8 fired. |
| 9 |
| 10 ```dart |
| 11 class DeadlineExceededException implements Exception { } |
| 12 ``` |
| 13 |
| 14 When Sky is to *process a task queue until a particular time*, with a |
| 15 queue *relevant task queue*, bits *filter bits*, a time |
| 16 *particular time*, and an *idle rule* which is either "sleep" or |
| 17 "abort", it must run the following steps: |
| 18 |
| 19 1. Let *remaining time* be the time until the given *particular time*. |
| 20 2. If *remaining time* is less than or equal to zero, exit this |
| 21 algorithm. |
| 22 3. Let *task list* be the list of tasks in the *relevant task queue* |
| 23 that have bits that, when 'or'ed with *filter bits*, are non-zero; |
| 24 whose required budget is less than or equal to *remaining time*; |
| 25 and whose due time, if any, has been reached. |
| 26 4. If *task list* is empty, then if *idle rule* is "sleep" then return |
| 27 to step 1, otherwise, exit this algorithm. |
| 28 5. Sort *task list* by the priority of each task, highest first. |
| 29 6. Remove the top task from *task list* from the *relevant task |
| 30 queue*, and let that be *selected task*. |
| 31 7. Run *selected task*, with a budget of *remaining time* or 1ms, |
| 32 whichever is shorter. |
| 33 8. Return to step 1. |
| 34 |
| 35 When Sky is to *drain a task queue for a specified time*, with a queue |
| 36 *relevant task queue*, bits *filter bits*, and a duration *budget*, it |
| 37 must run the following steps: |
| 38 |
| 39 2. Let *task list* be the list of tasks in the *relevant task queue* |
| 40 that have bits that, when 'or'ed with *filter bits*, are non-zero; |
| 41 and whose required budget is less than or equal to *budget*. |
| 42 4. If *task list* is empty, then exit. |
| 43 5. Sort *task list* by the priority of each task, highest first. |
| 44 6. Remove the top task from *task list* from the *relevant task |
| 45 queue*, and let that be *selected task*. |
| 46 7. Run *selected task*, with a budget of *budget*. |
| 47 8. Decrease *budget* with the amount of time that *selected task* took |
| 48 to run. |
| 49 9. If *selected task* threw an uncaught DeadlineExceededException |
| 50 exception, then cancel all the tasks in *relevant task queue*. |
| 51 Otherwise, return to step 2. |
| 52 |
| 4 Sky's run loop consists of running the following, at 120Hz (each loop | 53 Sky's run loop consists of running the following, at 120Hz (each loop |
| 5 takes 8.333ms): | 54 takes 8.333ms): |
| 6 | 55 |
| 7 1. Send scroll and resize events if necessary, limiting each handler | 56 1. *Drain* the *paint task queue*, with bits |
| 8 to 1ms, and limiting the total time spent on these handlers to 1ms. | 57 `application.paintTaskBits`, for 1ms. |
| 9 | 58 |
| 10 2. Fire animation frame callbacks for up to 1ms. Each callback can run | 59 2. Create a task that does the following, then run it with a budget of |
| 11 for up to 1ms. Once 1ms has expired, throw a (catchable) | 60 1ms: |
| 12 EDeadlineExceeded exception. If it's not caught, drop subsequent | |
| 13 callbacks. | |
| 14 | 61 |
| 15 4. Spend up to 1ms to update the render tree, including calling | 62 1. Update the render tree, including calling childAdded(), |
| 16 childAdded(), childRemoved(), and getLayoutManager() as needed. | 63 childRemoved(), and getLayoutManager() as needed, catching any |
| 17 Once 1ms has expired, throw a (catchable) EDeadlineExceeded | 64 exceptions other than DeadlineExceededException exceptions. |
| 18 exception, leaving the render tree in whatever state it has | |
| 19 reached. | |
| 20 | 65 |
| 21 3. Update the ElementStyleDeclarationList objects for all elements on | 66 If an exception is thrown by this, then the RenderNode tree will |
| 22 the RenderTree. | 67 continue to not quite match the element tree, which is fine. |
| 23 | 68 |
| 24 5. Update as much of layout as possible; after 1ms, throw a | 69 3. If there are no tasks on the *idle task queue* with bits |
| 25 (catchable) EDeadlineExceeded exception, leaving the remaining | 70 `LayoutKind`, create a task that tells the root node to layout if |
| 26 nodes unprepared. | 71 it has needsLayout or descendantNeedsLayout, mark that with |
| 72 priority 0 and bits `LayoutKind`, and add it to the *idle task |
| 73 queue*. |
| 27 | 74 |
| 28 6. Update as much of paint as possible; after 1ms, throw a (catchable) | 75 4. *Process* the *idle task queue*, with bits `LayoutKind`, with a |
| 29 EDeadlineExceeded exception, leaving any remaining nodes | 76 target time of t-1ms, where t is the time at which we have to send |
| 30 unprepared. | 77 the frame to the GPU, and with an *idle rule* of "abort". |
| 31 | 78 |
| 32 7. Send frame to GPU. | 79 5. Create a task that does the following, then run it with a budget of |
| 80 1ms: |
| 33 | 81 |
| 34 8. Run pending tasks until the 8.333ms expires. Each task may only run | 82 1. If there are no RenderNodes that need paint, abort. |
| 35 for at most 1ms, after 1ms they get a (catchable) EDeadlineExceeded | 83 |
| 36 exception. While there are no pending tasks, sleep. | 84 2. Call the `paint()` callback of the RenderNode that was least |
| 37 Tasks are things like: | 85 recently marked as needing paint, catching any exceptions other |
| 38 - timers | 86 than DeadlineExceededException exceptions. |
| 39 - updating the DOM in response to parsing | 87 |
| 40 - input events | 88 3. Jump to step 1. |
| 41 - mojo callbacks | 89 |
| 90 If an exception is thrown by this, then some RenderNode objects |
| 91 will be out-of-date during the paint. |
| 92 |
| 93 6. Send frame to GPU. |
| 94 |
| 95 7. Replace the paint queue with the nextPaint queue, and let the |
| 96 nextPaint queue be an empty queue. |
| 97 |
| 98 8. *Process* the *idle task queue*, with bits |
| 99 `application.idleTaskBits`, with a target time of t, where t is the |
| 100 time at which we have to start the next frame's layout and paint |
| 101 computations, and with an *idle rule* of "sleep". |
| 42 | 102 |
| 43 TODO(ianh): Update the timings above to have some relationship to | 103 TODO(ianh): Update the timings above to have some relationship to |
| 44 reality. | 104 reality. |
| 45 | 105 |
| 46 TODO(ianh): Define an API so that the application can adjust the | 106 TODO(ianh): Define an API so that the application can adjust the |
| 47 budgets. | 107 budgets. |
| 48 | 108 |
| 49 TODO(ianh): Define how scroll notifications get sent, or decide to | 109 Task kinds and priorities |
| 50 drop them entirely from this model. | 110 ------------------------- |
| 111 |
| 112 ```dart |
| 113 const IdlePriority = 0; |
| 114 const FuturePriority = 10000; // the tasks scheduled by futures resolving have t
his priority |
| 115 |
| 116 const IdleKind = 0x01; // tasks that should run during the idle loop |
| 117 const LayoutKind = 0x02; // tasks that should run during layout |
| 118 const PaintQueueKind = 0x04; // tasks that run on the paint queue |
| 119 |
| 120 int idleTaskBits = IdleKind; |
| 121 int paintTaskBits = PaintQueueKind; |
| 122 ``` |
| OLD | NEW |