diff options
author | Lukas Toenne <lukas.toenne@googlemail.com> | 2012-09-11 15:41:51 +0400 |
---|---|---|
committer | Lukas Toenne <lukas.toenne@googlemail.com> | 2012-09-11 15:41:51 +0400 |
commit | 31ed71cb6b86278eb5c15de65eb8e2ed800821e1 (patch) | |
tree | 9ce654327b030ee0351a8aacf2ef17cdd18c4a1d /intern/cycles/util/util_task.cpp | |
parent | 2cdfa33137b69b82c8354dd5d0bd58acfe2d89d9 (diff) |
Performance fix for Cycles: Don't wait in the main UI thread when resetting devices.
When the scene is updated Cycles resets the renderer device, cancelling
all existing tasks. The main thread would wait for all running tasks to
finish before continuing. This is ok when tasks can actually cancel in a
timely fashion. For OSL however, this does not work, since the OSL
shader group optimization takes quite a bit of time and can not be
easily be cancelled once running (on my crappy machine in full debug
mode: ~0.12 seconds for simple node trees). This would lead to very
laggy UI behavior and make it difficult to accurately control elements
such as sliders.
This patch removes the wait condition from the device->task_cancel
method. Instead it just sets the do_cancel flag and returns. To avoid
backlog in the task pool of the device it will return early from the
BlenderSession::sync function while the reset is going on (tested in
Session::resetting). Once all existing tasks have finished the do_cancel
flag is finally cleared again (checked in TaskPool::num_decrease).
Care has to be taken to avoid race conditions on the do_cancel flag,
since it can now be modified outside the TaskPool::cancel function
itself. For this purpose the scope of the TaskPool::num_mutex locks has
been extended, in most cases the mutex is now locked by the TaskPool
itself before calling TaskScheduler methods, instead of only locking
inside the num_increase/num_decrease functions themselves. The only
occurrence of a lock outside of the TaskPool methods is in
TaskScheduler::thread_run.
This patch is most useful in combination with the OSL renderer mode, so
it can probably wait until after the 2.64 release. SVM tasks tend to be
cancelled quickly, so the effect is less noticeable.
Diffstat (limited to 'intern/cycles/util/util_task.cpp')
-rw-r--r-- | intern/cycles/util/util_task.cpp | 33 |
1 files changed, 17 insertions, 16 deletions
diff --git a/intern/cycles/util/util_task.cpp b/intern/cycles/util/util_task.cpp index ea0abd6f54f..2b209c135f4 100644 --- a/intern/cycles/util/util_task.cpp +++ b/intern/cycles/util/util_task.cpp @@ -38,6 +38,8 @@ TaskPool::~TaskPool() void TaskPool::push(Task *task, bool front) { + thread_scoped_lock num_lock(num_mutex); + TaskScheduler::Entry entry; entry.task = task; @@ -102,22 +104,17 @@ void TaskPool::wait_work() void TaskPool::cancel() { + thread_scoped_lock num_lock(num_mutex); + do_cancel = true; TaskScheduler::clear(this); - - { - thread_scoped_lock num_lock(num_mutex); - - while(num) - num_cond.wait(num_lock); - } - - do_cancel = false; } void TaskPool::stop() { + thread_scoped_lock num_lock(num_mutex); + TaskScheduler::clear(this); assert(num == 0); @@ -130,20 +127,20 @@ bool TaskPool::cancelled() void TaskPool::num_decrease(int done) { - num_mutex.lock(); num -= done; - assert(num >= 0); - if(num == 0) + + if(num == 0) { + do_cancel = false; + num_cond.notify_all(); - - num_mutex.unlock(); + } } void TaskPool::num_increase() { - thread_scoped_lock num_lock(num_mutex); num++; + num_cond.notify_all(); } @@ -239,7 +236,11 @@ void TaskScheduler::thread_run(int thread_id) delete entry.task; /* notify pool task was done */ - entry.pool->num_decrease(1); + { + /* not called from TaskPool, have to explicitly lock the mutex here */ + thread_scoped_lock num_lock(entry.pool->num_mutex); + entry.pool->num_decrease(1); + } } } |