Cycles: pause button to interrupt viewport renders, in the 3d view header.

This commit is contained in:
Brecht Van Lommel
2011-08-29 16:54:13 +00:00
parent 213c58fdd5
commit be0aef2ef2
8 changed files with 140 additions and 63 deletions

View File

@@ -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",

View File

@@ -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')

View File

@@ -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)

View File

@@ -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;

View File

@@ -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 */

View File

@@ -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;
} }

View File

@@ -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);
} }

View File

@@ -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