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.
This commit is contained in:
parent
2cdfa33137
commit
31ed71cb6b
@ -372,6 +372,12 @@ void BlenderSession::synchronize()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* if the session is still resetting the device come back later */
|
||||||
|
if(session->resetting()) {
|
||||||
|
tag_update();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* increase samples, but never decrease */
|
/* increase samples, but never decrease */
|
||||||
session->set_samples(session_params.samples);
|
session->set_samples(session_params.samples);
|
||||||
session->set_pause(BlenderSync::get_session_pause(b_scene, background));
|
session->set_pause(BlenderSync::get_session_pause(b_scene, background));
|
||||||
|
@ -115,6 +115,7 @@ public:
|
|||||||
virtual void task_add(DeviceTask& task) = 0;
|
virtual void task_add(DeviceTask& task) = 0;
|
||||||
virtual void task_wait() = 0;
|
virtual void task_wait() = 0;
|
||||||
virtual void task_cancel() = 0;
|
virtual void task_cancel() = 0;
|
||||||
|
virtual bool task_cancelled() = 0;
|
||||||
|
|
||||||
/* opengl drawing */
|
/* opengl drawing */
|
||||||
virtual void draw_pixels(device_memory& mem, int y, int w, int h,
|
virtual void draw_pixels(device_memory& mem, int y, int w, int h,
|
||||||
|
@ -273,6 +273,11 @@ public:
|
|||||||
{
|
{
|
||||||
task_pool.cancel();
|
task_pool.cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool task_cancelled()
|
||||||
|
{
|
||||||
|
return task_pool.cancelled();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Device *device_cpu_create(DeviceInfo& info, int threads)
|
Device *device_cpu_create(DeviceInfo& info, int threads)
|
||||||
|
@ -892,6 +892,11 @@ public:
|
|||||||
{
|
{
|
||||||
task_pool.cancel();
|
task_pool.cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool task_cancelled()
|
||||||
|
{
|
||||||
|
return task_pool.cancelled();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Device *device_cuda_create(DeviceInfo& info, bool background)
|
Device *device_cuda_create(DeviceInfo& info, bool background)
|
||||||
|
@ -312,6 +312,14 @@ public:
|
|||||||
foreach(SubDevice& sub, devices)
|
foreach(SubDevice& sub, devices)
|
||||||
sub.device->task_cancel();
|
sub.device->task_cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool task_cancelled()
|
||||||
|
{
|
||||||
|
foreach(SubDevice& sub, devices)
|
||||||
|
if (sub.device->task_cancelled())
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Device *device_multi_create(DeviceInfo& info, bool background)
|
Device *device_multi_create(DeviceInfo& info, bool background)
|
||||||
|
@ -724,6 +724,11 @@ public:
|
|||||||
{
|
{
|
||||||
task_pool.cancel();
|
task_pool.cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool task_cancelled()
|
||||||
|
{
|
||||||
|
return task_pool.cancelled();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Device *device_opencl_create(DeviceInfo& info, bool background)
|
Device *device_opencl_create(DeviceInfo& info, bool background)
|
||||||
|
@ -140,6 +140,12 @@ void Session::reset_gpu(BufferParams& buffer_params, int samples)
|
|||||||
pause_cond.notify_all();
|
pause_cond.notify_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Session::resetting_gpu() const
|
||||||
|
{
|
||||||
|
/* no need to wait for gpu device */
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool Session::draw_gpu(BufferParams& buffer_params)
|
bool Session::draw_gpu(BufferParams& buffer_params)
|
||||||
{
|
{
|
||||||
/* block for buffer access */
|
/* block for buffer access */
|
||||||
@ -290,6 +296,11 @@ void Session::reset_cpu(BufferParams& buffer_params, int samples)
|
|||||||
pause_cond.notify_all();
|
pause_cond.notify_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Session::resetting_cpu() const
|
||||||
|
{
|
||||||
|
return device->task_cancelled();
|
||||||
|
}
|
||||||
|
|
||||||
bool Session::draw_cpu(BufferParams& buffer_params)
|
bool Session::draw_cpu(BufferParams& buffer_params)
|
||||||
{
|
{
|
||||||
thread_scoped_lock display_lock(display_mutex);
|
thread_scoped_lock display_lock(display_mutex);
|
||||||
@ -584,6 +595,14 @@ void Session::reset(BufferParams& buffer_params, int samples)
|
|||||||
reset_cpu(buffer_params, samples);
|
reset_cpu(buffer_params, samples);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Session::resetting() const
|
||||||
|
{
|
||||||
|
if(device_use_gl)
|
||||||
|
return resetting_gpu();
|
||||||
|
else
|
||||||
|
return resetting_cpu();
|
||||||
|
}
|
||||||
|
|
||||||
void Session::set_samples(int samples)
|
void Session::set_samples(int samples)
|
||||||
{
|
{
|
||||||
if(samples != params.samples) {
|
if(samples != params.samples) {
|
||||||
|
@ -116,6 +116,7 @@ public:
|
|||||||
|
|
||||||
bool ready_to_reset();
|
bool ready_to_reset();
|
||||||
void reset(BufferParams& params, int samples);
|
void reset(BufferParams& params, int samples);
|
||||||
|
bool resetting() const;
|
||||||
void set_samples(int samples);
|
void set_samples(int samples);
|
||||||
void set_pause(bool pause);
|
void set_pause(bool pause);
|
||||||
|
|
||||||
@ -139,10 +140,12 @@ protected:
|
|||||||
void run_cpu();
|
void run_cpu();
|
||||||
bool draw_cpu(BufferParams& params);
|
bool draw_cpu(BufferParams& params);
|
||||||
void reset_cpu(BufferParams& params, int samples);
|
void reset_cpu(BufferParams& params, int samples);
|
||||||
|
bool resetting_cpu() const;
|
||||||
|
|
||||||
void run_gpu();
|
void run_gpu();
|
||||||
bool draw_gpu(BufferParams& params);
|
bool draw_gpu(BufferParams& params);
|
||||||
void reset_gpu(BufferParams& params, int samples);
|
void reset_gpu(BufferParams& params, int samples);
|
||||||
|
bool resetting_gpu() const;
|
||||||
|
|
||||||
bool acquire_tile(Device *tile_device, RenderTile& tile);
|
bool acquire_tile(Device *tile_device, RenderTile& tile);
|
||||||
void update_tile_sample(RenderTile& tile);
|
void update_tile_sample(RenderTile& tile);
|
||||||
|
@ -38,6 +38,8 @@ TaskPool::~TaskPool()
|
|||||||
|
|
||||||
void TaskPool::push(Task *task, bool front)
|
void TaskPool::push(Task *task, bool front)
|
||||||
{
|
{
|
||||||
|
thread_scoped_lock num_lock(num_mutex);
|
||||||
|
|
||||||
TaskScheduler::Entry entry;
|
TaskScheduler::Entry entry;
|
||||||
|
|
||||||
entry.task = task;
|
entry.task = task;
|
||||||
@ -102,22 +104,17 @@ void TaskPool::wait_work()
|
|||||||
|
|
||||||
void TaskPool::cancel()
|
void TaskPool::cancel()
|
||||||
{
|
{
|
||||||
|
thread_scoped_lock num_lock(num_mutex);
|
||||||
|
|
||||||
do_cancel = true;
|
do_cancel = true;
|
||||||
|
|
||||||
TaskScheduler::clear(this);
|
TaskScheduler::clear(this);
|
||||||
|
|
||||||
{
|
|
||||||
thread_scoped_lock num_lock(num_mutex);
|
|
||||||
|
|
||||||
while(num)
|
|
||||||
num_cond.wait(num_lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
do_cancel = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TaskPool::stop()
|
void TaskPool::stop()
|
||||||
{
|
{
|
||||||
|
thread_scoped_lock num_lock(num_mutex);
|
||||||
|
|
||||||
TaskScheduler::clear(this);
|
TaskScheduler::clear(this);
|
||||||
|
|
||||||
assert(num == 0);
|
assert(num == 0);
|
||||||
@ -130,20 +127,20 @@ bool TaskPool::cancelled()
|
|||||||
|
|
||||||
void TaskPool::num_decrease(int done)
|
void TaskPool::num_decrease(int done)
|
||||||
{
|
{
|
||||||
num_mutex.lock();
|
|
||||||
num -= done;
|
num -= done;
|
||||||
|
|
||||||
assert(num >= 0);
|
assert(num >= 0);
|
||||||
if(num == 0)
|
|
||||||
|
if(num == 0) {
|
||||||
|
do_cancel = false;
|
||||||
|
|
||||||
num_cond.notify_all();
|
num_cond.notify_all();
|
||||||
|
}
|
||||||
num_mutex.unlock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TaskPool::num_increase()
|
void TaskPool::num_increase()
|
||||||
{
|
{
|
||||||
thread_scoped_lock num_lock(num_mutex);
|
|
||||||
num++;
|
num++;
|
||||||
|
|
||||||
num_cond.notify_all();
|
num_cond.notify_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -239,7 +236,11 @@ void TaskScheduler::thread_run(int thread_id)
|
|||||||
delete entry.task;
|
delete entry.task;
|
||||||
|
|
||||||
/* notify pool task was done */
|
/* 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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user