Cycles: pause button to interrupt viewport renders, in the 3d view header.
This commit is contained in:
@@ -36,6 +36,9 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
|
|||||||
default=10, min=1, max=2147483647)
|
default=10, min=1, max=2147483647)
|
||||||
cls.preview_passes = IntProperty(name="Preview Passes", description="Number of passes to render in the viewport, unlimited if 0",
|
cls.preview_passes = IntProperty(name="Preview Passes", description="Number of passes to render in the viewport, unlimited if 0",
|
||||||
default=0, min=0, max=2147483647)
|
default=0, min=0, max=2147483647)
|
||||||
|
cls.preview_pause = BoolProperty(name="Pause Preview", description="Pause all viewport preview renders",
|
||||||
|
default=False)
|
||||||
|
|
||||||
cls.min_bounces = IntProperty(name="Min Bounces", description="Minimum number of bounces",
|
cls.min_bounces = IntProperty(name="Min Bounces", description="Minimum number of bounces",
|
||||||
default=3, min=0, max=1024)
|
default=3, min=0, max=1024)
|
||||||
cls.max_bounces = IntProperty(name="Max Bounces", description="Maximum number of bounces",
|
cls.max_bounces = IntProperty(name="Max Bounces", description="Maximum number of bounces",
|
||||||
|
@@ -473,6 +473,17 @@ def draw_device(self, context):
|
|||||||
if cscene.device == 'CPU' and engine.with_osl():
|
if cscene.device == 'CPU' and engine.with_osl():
|
||||||
layout.prop(cscene, "shading_system")
|
layout.prop(cscene, "shading_system")
|
||||||
|
|
||||||
|
def draw_pause(self, context):
|
||||||
|
layout = self.layout
|
||||||
|
scene = context.scene
|
||||||
|
|
||||||
|
if scene.render.engine == "CYCLES":
|
||||||
|
view = context.space_data
|
||||||
|
|
||||||
|
if view.viewport_shade == "RENDERED":
|
||||||
|
cscene = scene.cycles
|
||||||
|
layout.prop(cscene, "preview_pause", icon="PAUSE", text="")
|
||||||
|
|
||||||
def get_panels():
|
def get_panels():
|
||||||
return [
|
return [
|
||||||
bpy.types.RENDER_PT_render,
|
bpy.types.RENDER_PT_render,
|
||||||
@@ -514,12 +525,14 @@ def get_panels():
|
|||||||
|
|
||||||
def register():
|
def register():
|
||||||
bpy.types.RENDER_PT_render.append(draw_device)
|
bpy.types.RENDER_PT_render.append(draw_device)
|
||||||
|
bpy.types.VIEW3D_HT_header.append(draw_pause)
|
||||||
|
|
||||||
for panel in get_panels():
|
for panel in get_panels():
|
||||||
panel.COMPAT_ENGINES.add('CYCLES')
|
panel.COMPAT_ENGINES.add('CYCLES')
|
||||||
|
|
||||||
def unregister():
|
def unregister():
|
||||||
bpy.types.RENDER_PT_render.remove(draw_device)
|
bpy.types.RENDER_PT_render.remove(draw_device)
|
||||||
|
bpy.types.VIEW3D_HT_header.remove(draw_pause)
|
||||||
|
|
||||||
for panel in get_panels():
|
for panel in get_panels():
|
||||||
panel.COMPAT_ENGINES.remove('CYCLES')
|
panel.COMPAT_ENGINES.remove('CYCLES')
|
||||||
|
@@ -93,6 +93,7 @@ void BlenderSession::create_session()
|
|||||||
session->scene = scene;
|
session->scene = scene;
|
||||||
session->progress.set_update_callback(function_bind(&BlenderSession::tag_redraw, this));
|
session->progress.set_update_callback(function_bind(&BlenderSession::tag_redraw, this));
|
||||||
session->progress.set_cancel_callback(function_bind(&BlenderSession::test_cancel, this));
|
session->progress.set_cancel_callback(function_bind(&BlenderSession::test_cancel, this));
|
||||||
|
session->set_pause(BlenderSync::get_session_pause(b_scene, background));
|
||||||
|
|
||||||
/* start rendering */
|
/* start rendering */
|
||||||
session->reset(width, height, session_params.passes);
|
session->reset(width, height, session_params.passes);
|
||||||
@@ -159,6 +160,7 @@ void BlenderSession::synchronize()
|
|||||||
|
|
||||||
/* increase passes, but never decrease */
|
/* increase passes, but never decrease */
|
||||||
session->set_passes(session_params.passes);
|
session->set_passes(session_params.passes);
|
||||||
|
session->set_pause(BlenderSync::get_session_pause(b_scene, background));
|
||||||
|
|
||||||
/* copy recalc flags, outside of mutex so we can decide to do the real
|
/* copy recalc flags, outside of mutex so we can decide to do the real
|
||||||
synchronization at a later time to not block on running updates */
|
synchronization at a later time to not block on running updates */
|
||||||
@@ -178,12 +180,12 @@ void BlenderSession::synchronize()
|
|||||||
else
|
else
|
||||||
sync->sync_camera(width, height);
|
sync->sync_camera(width, height);
|
||||||
|
|
||||||
|
/* unlock */
|
||||||
|
session->scene->mutex.unlock();
|
||||||
|
|
||||||
/* reset if needed */
|
/* reset if needed */
|
||||||
if(scene->need_reset())
|
if(scene->need_reset())
|
||||||
session->reset(width, height, session_params.passes);
|
session->reset(width, height, session_params.passes);
|
||||||
|
|
||||||
/* unlock */
|
|
||||||
session->scene->mutex.unlock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BlenderSession::draw(int w, int h)
|
bool BlenderSession::draw(int w, int h)
|
||||||
|
@@ -185,6 +185,12 @@ SceneParams BlenderSync::get_scene_params(BL::Scene b_scene)
|
|||||||
|
|
||||||
/* Session Parameters */
|
/* Session Parameters */
|
||||||
|
|
||||||
|
bool BlenderSync::get_session_pause(BL::Scene b_scene, bool background)
|
||||||
|
{
|
||||||
|
PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
|
||||||
|
return (background)? false: get_boolean(cscene, "preview_pause");
|
||||||
|
}
|
||||||
|
|
||||||
SessionParams BlenderSync::get_session_params(BL::Scene b_scene, bool background)
|
SessionParams BlenderSync::get_session_params(BL::Scene b_scene, bool background)
|
||||||
{
|
{
|
||||||
SessionParams params;
|
SessionParams params;
|
||||||
|
@@ -61,6 +61,7 @@ public:
|
|||||||
/* get parameters */
|
/* get parameters */
|
||||||
static SceneParams get_scene_params(BL::Scene b_scene);
|
static SceneParams get_scene_params(BL::Scene b_scene);
|
||||||
static SessionParams get_session_params(BL::Scene b_scene, bool background);
|
static SessionParams get_session_params(BL::Scene b_scene, bool background);
|
||||||
|
static bool get_session_pause(BL::Scene b_scene, bool background);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/* sync */
|
/* sync */
|
||||||
|
@@ -57,31 +57,31 @@ Scene::Scene(const SceneParams& params_)
|
|||||||
|
|
||||||
Scene::~Scene()
|
Scene::~Scene()
|
||||||
{
|
{
|
||||||
camera->device_free(device, &dscene);
|
if(device) camera->device_free(device, &dscene);
|
||||||
delete camera;
|
delete camera;
|
||||||
|
|
||||||
filter->device_free(device, &dscene);
|
if(device) filter->device_free(device, &dscene);
|
||||||
delete filter;
|
delete filter;
|
||||||
|
|
||||||
film->device_free(device, &dscene);
|
if(device) film->device_free(device, &dscene);
|
||||||
delete film;
|
delete film;
|
||||||
|
|
||||||
background->device_free(device, &dscene);
|
if(device) background->device_free(device, &dscene);
|
||||||
delete background;
|
delete background;
|
||||||
|
|
||||||
mesh_manager->device_free(device, &dscene);
|
if(device) mesh_manager->device_free(device, &dscene);
|
||||||
delete mesh_manager;
|
delete mesh_manager;
|
||||||
|
|
||||||
object_manager->device_free(device, &dscene);
|
if(device) object_manager->device_free(device, &dscene);
|
||||||
delete object_manager;
|
delete object_manager;
|
||||||
|
|
||||||
integrator->device_free(device, &dscene);
|
if(device) integrator->device_free(device, &dscene);
|
||||||
delete integrator;
|
delete integrator;
|
||||||
|
|
||||||
shader_manager->device_free(device, &dscene);
|
if(device) shader_manager->device_free(device, &dscene);
|
||||||
delete shader_manager;
|
delete shader_manager;
|
||||||
|
|
||||||
light_manager->device_free(device, &dscene);
|
if(device) light_manager->device_free(device, &dscene);
|
||||||
delete light_manager;
|
delete light_manager;
|
||||||
|
|
||||||
foreach(Shader *s, shaders)
|
foreach(Shader *s, shaders)
|
||||||
@@ -93,7 +93,7 @@ Scene::~Scene()
|
|||||||
foreach(Light *l, lights)
|
foreach(Light *l, lights)
|
||||||
delete l;
|
delete l;
|
||||||
|
|
||||||
image_manager->device_free(device, &dscene);
|
if(device) image_manager->device_free(device, &dscene);
|
||||||
delete image_manager;
|
delete image_manager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -47,6 +47,7 @@ Session::Session(const SessionParams& params_)
|
|||||||
start_time = 0.0;
|
start_time = 0.0;
|
||||||
reset_time = 0.0;
|
reset_time = 0.0;
|
||||||
preview_time = 0.0;
|
preview_time = 0.0;
|
||||||
|
paused_time = 0.0;
|
||||||
pass = 0;
|
pass = 0;
|
||||||
|
|
||||||
delayed_reset.do_reset = false;
|
delayed_reset.do_reset = false;
|
||||||
@@ -64,9 +65,16 @@ Session::~Session()
|
|||||||
{
|
{
|
||||||
if(session_thread) {
|
if(session_thread) {
|
||||||
progress.set_cancel("Exiting");
|
progress.set_cancel("Exiting");
|
||||||
|
|
||||||
gpu_need_tonemap = false;
|
gpu_need_tonemap = false;
|
||||||
gpu_need_tonemap_cond.notify_all();
|
gpu_need_tonemap_cond.notify_all();
|
||||||
set_pause(false);
|
|
||||||
|
{
|
||||||
|
thread_scoped_lock pause_lock(pause_mutex);
|
||||||
|
pause = false;
|
||||||
|
}
|
||||||
|
pause_cond.notify_all();
|
||||||
|
|
||||||
wait();
|
wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,40 +160,54 @@ void Session::run_gpu()
|
|||||||
{
|
{
|
||||||
start_time = time_dt();
|
start_time = time_dt();
|
||||||
reset_time = time_dt();
|
reset_time = time_dt();
|
||||||
|
paused_time = 0.0;
|
||||||
|
|
||||||
while(!progress.get_cancel()) {
|
while(!progress.get_cancel()) {
|
||||||
/* advance to next tile */
|
/* advance to next tile */
|
||||||
bool done = !tile_manager.next();
|
bool no_tiles = !tile_manager.next();
|
||||||
|
|
||||||
/* any work left? */
|
|
||||||
if(done) {
|
|
||||||
/* if in background mode, we can stop immediately */
|
|
||||||
if(params.background) {
|
if(params.background) {
|
||||||
|
/* if no work left and in background mode, we can stop immediately */
|
||||||
|
if(no_tiles)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* in interactive mode, we wait until woken up */
|
/* if in interactive mode, and we are either paused or done for now,
|
||||||
|
wait for pause condition notify to wake up again */
|
||||||
thread_scoped_lock pause_lock(pause_mutex);
|
thread_scoped_lock pause_lock(pause_mutex);
|
||||||
|
|
||||||
|
if(pause || no_tiles) {
|
||||||
|
update_status_time(pause, no_tiles);
|
||||||
|
|
||||||
|
while(1) {
|
||||||
|
double pause_start = time_dt();
|
||||||
pause_cond.wait(pause_lock);
|
pause_cond.wait(pause_lock);
|
||||||
|
paused_time += time_dt() - pause_start;
|
||||||
|
|
||||||
|
update_status_time(pause, no_tiles);
|
||||||
|
progress.set_update();
|
||||||
|
|
||||||
|
if(!pause)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
/* test for pause and wait until woken up */
|
|
||||||
thread_scoped_lock pause_lock(pause_mutex);
|
|
||||||
while(pause)
|
|
||||||
pause_cond.wait(pause_lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
if(progress.get_cancel())
|
||||||
/* buffers mutex is locked entirely while rendering each
|
break;
|
||||||
pass, and released/reacquired on each iteration to allow
|
}
|
||||||
reset and draw in between */
|
|
||||||
thread_scoped_lock buffers_lock(buffers->mutex);
|
|
||||||
|
|
||||||
|
if(!no_tiles) {
|
||||||
/* update scene */
|
/* update scene */
|
||||||
update_scene();
|
update_scene();
|
||||||
if(progress.get_cancel())
|
if(progress.get_cancel())
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!no_tiles) {
|
||||||
|
/* buffers mutex is locked entirely while rendering each
|
||||||
|
pass, and released/reacquired on each iteration to allow
|
||||||
|
reset and draw in between */
|
||||||
|
thread_scoped_lock buffers_lock(buffers->mutex);
|
||||||
|
|
||||||
/* update status and timing */
|
/* update status and timing */
|
||||||
update_status_time();
|
update_status_time();
|
||||||
@@ -276,29 +298,40 @@ void Session::run_cpu()
|
|||||||
|
|
||||||
while(!progress.get_cancel()) {
|
while(!progress.get_cancel()) {
|
||||||
/* advance to next tile */
|
/* advance to next tile */
|
||||||
bool done = !tile_manager.next();
|
bool no_tiles = !tile_manager.next();
|
||||||
bool need_tonemap = false;
|
bool need_tonemap = false;
|
||||||
|
|
||||||
/* any work left? */
|
|
||||||
if(done) {
|
|
||||||
/* if in background mode, we can stop immediately */
|
|
||||||
if(params.background) {
|
if(params.background) {
|
||||||
|
/* if no work left and in background mode, we can stop immediately */
|
||||||
|
if(no_tiles)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* in interactive mode, we wait until woken up */
|
/* if in interactive mode, and we are either paused or done for now,
|
||||||
|
wait for pause condition notify to wake up again */
|
||||||
thread_scoped_lock pause_lock(pause_mutex);
|
thread_scoped_lock pause_lock(pause_mutex);
|
||||||
|
|
||||||
|
if(pause || no_tiles) {
|
||||||
|
update_status_time(pause, no_tiles);
|
||||||
|
|
||||||
|
while(1) {
|
||||||
|
double pause_start = time_dt();
|
||||||
pause_cond.wait(pause_lock);
|
pause_cond.wait(pause_lock);
|
||||||
|
paused_time += time_dt() - pause_start;
|
||||||
|
|
||||||
|
update_status_time(pause, no_tiles);
|
||||||
|
progress.set_update();
|
||||||
|
|
||||||
|
if(!pause)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
/* test for pause and wait until woken up */
|
|
||||||
thread_scoped_lock pause_lock(pause_mutex);
|
|
||||||
while(pause)
|
|
||||||
pause_cond.wait(pause_lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!done) {
|
if(progress.get_cancel())
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!no_tiles) {
|
||||||
/* buffers mutex is locked entirely while rendering each
|
/* buffers mutex is locked entirely while rendering each
|
||||||
pass, and released/reacquired on each iteration to allow
|
pass, and released/reacquired on each iteration to allow
|
||||||
reset and draw in between */
|
reset and draw in between */
|
||||||
@@ -350,12 +383,6 @@ void Session::run()
|
|||||||
/* session thread loop */
|
/* session thread loop */
|
||||||
progress.set_status("Waiting for render to start");
|
progress.set_status("Waiting for render to start");
|
||||||
|
|
||||||
/* first scene update */
|
|
||||||
if(!progress.get_cancel()) {
|
|
||||||
thread_scoped_lock scene_lock(scene->mutex);
|
|
||||||
scene->device_update(device, progress);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* run */
|
/* run */
|
||||||
if(!progress.get_cancel()) {
|
if(!progress.get_cancel()) {
|
||||||
if(device_use_gl)
|
if(device_use_gl)
|
||||||
@@ -391,6 +418,7 @@ void Session::reset_(int w, int h, int passes)
|
|||||||
|
|
||||||
start_time = time_dt();
|
start_time = time_dt();
|
||||||
preview_time = 0.0;
|
preview_time = 0.0;
|
||||||
|
paused_time = 0.0;
|
||||||
pass = 0;
|
pass = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -408,17 +436,27 @@ void Session::set_passes(int passes)
|
|||||||
params.passes = passes;
|
params.passes = passes;
|
||||||
tile_manager.set_passes(passes);
|
tile_manager.set_passes(passes);
|
||||||
|
|
||||||
|
{
|
||||||
|
thread_scoped_lock pause_lock(pause_mutex);
|
||||||
|
}
|
||||||
pause_cond.notify_all();
|
pause_cond.notify_all();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Session::set_pause(bool pause_)
|
void Session::set_pause(bool pause_)
|
||||||
{
|
{
|
||||||
|
bool notify = false;
|
||||||
|
|
||||||
{
|
{
|
||||||
thread_scoped_lock pause_lock(pause_mutex);
|
thread_scoped_lock pause_lock(pause_mutex);
|
||||||
|
|
||||||
|
if(pause != pause_) {
|
||||||
pause = pause_;
|
pause = pause_;
|
||||||
|
notify = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(notify)
|
||||||
pause_cond.notify_all();
|
pause_cond.notify_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -452,27 +490,40 @@ void Session::update_scene()
|
|||||||
scene->device_update(device, progress);
|
scene->device_update(device, progress);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Session::update_status_time()
|
void Session::update_status_time(bool show_pause, bool show_done)
|
||||||
{
|
{
|
||||||
int pass = tile_manager.state.pass;
|
int pass = tile_manager.state.pass;
|
||||||
int resolution = tile_manager.state.resolution;
|
int resolution = tile_manager.state.resolution;
|
||||||
|
|
||||||
/* update status */
|
/* update status */
|
||||||
string substatus;
|
string status, substatus;
|
||||||
|
|
||||||
if(!params.progressive)
|
if(!params.progressive)
|
||||||
substatus = "Path Tracing";
|
substatus = "Path Tracing";
|
||||||
else if(params.passes == INT_MAX)
|
else if(params.passes == INT_MAX)
|
||||||
substatus = string_printf("Path Tracing Pass %d", pass+1);
|
substatus = string_printf("Path Tracing Pass %d", pass+1);
|
||||||
else
|
else
|
||||||
substatus = string_printf("Path Tracing Pass %d/%d", pass+1, params.passes);
|
substatus = string_printf("Path Tracing Pass %d/%d", pass+1, params.passes);
|
||||||
progress.set_status("Rendering", substatus);
|
|
||||||
|
if(show_pause)
|
||||||
|
status = "Paused";
|
||||||
|
else if(show_done)
|
||||||
|
status = "Done";
|
||||||
|
else
|
||||||
|
status = "Rendering";
|
||||||
|
|
||||||
|
progress.set_status(status, substatus);
|
||||||
|
|
||||||
/* update timing */
|
/* update timing */
|
||||||
if(preview_time == 0.0 && resolution == 1)
|
if(preview_time == 0.0 && resolution == 1)
|
||||||
preview_time = time_dt();
|
preview_time = time_dt();
|
||||||
|
|
||||||
double total_time = (time_dt() - start_time);
|
double total_time = time_dt() - start_time - paused_time;
|
||||||
double pass_time = (pass == 0)? 0.0: (time_dt() - preview_time)/(pass);
|
double pass_time = (pass == 0)? 0.0: (time_dt() - preview_time - paused_time)/(pass);
|
||||||
|
|
||||||
|
/* negative can happen when we pause a bit before rendering, can discard that */
|
||||||
|
if(total_time < 0.0) total_time = 0.0;
|
||||||
|
if(preview_time < 0.0) preview_time = 0.0;
|
||||||
|
|
||||||
progress.set_pass(pass + 1, total_time, pass_time);
|
progress.set_pass(pass + 1, total_time, pass_time);
|
||||||
}
|
}
|
||||||
|
@@ -122,7 +122,7 @@ protected:
|
|||||||
void run();
|
void run();
|
||||||
|
|
||||||
void update_scene();
|
void update_scene();
|
||||||
void update_status_time();
|
void update_status_time(bool show_pause = false, bool show_done = false);
|
||||||
|
|
||||||
void tonemap();
|
void tonemap();
|
||||||
void path_trace(Tile& tile);
|
void path_trace(Tile& tile);
|
||||||
@@ -154,6 +154,7 @@ protected:
|
|||||||
double start_time;
|
double start_time;
|
||||||
double reset_time;
|
double reset_time;
|
||||||
double preview_time;
|
double preview_time;
|
||||||
|
double paused_time;
|
||||||
};
|
};
|
||||||
|
|
||||||
CCL_NAMESPACE_END
|
CCL_NAMESPACE_END
|
||||||
|
Reference in New Issue
Block a user