From be0aef2ef24d0d84e199c59a91634e87cdef3d58 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Mon, 29 Aug 2011 16:54:13 +0000 Subject: Cycles: pause button to interrupt viewport renders, in the 3d view header. --- intern/cycles/blender/addon/properties.py | 3 + intern/cycles/blender/addon/ui.py | 13 +++ intern/cycles/blender/blender_session.cpp | 8 +- intern/cycles/blender/blender_sync.cpp | 6 ++ intern/cycles/blender/blender_sync.h | 1 + intern/cycles/render/scene.cpp | 20 ++-- intern/cycles/render/session.cpp | 149 ++++++++++++++++++++---------- intern/cycles/render/session.h | 3 +- 8 files changed, 140 insertions(+), 63 deletions(-) (limited to 'intern') diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py index 62c1db5a16d..b2d982fdabc 100644 --- a/intern/cycles/blender/addon/properties.py +++ b/intern/cycles/blender/addon/properties.py @@ -36,6 +36,9 @@ class CyclesRenderSettings(bpy.types.PropertyGroup): 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", 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", default=3, min=0, max=1024) cls.max_bounces = IntProperty(name="Max Bounces", description="Maximum number of bounces", diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index 4fe9e25d251..ec753590cce 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -473,6 +473,17 @@ def draw_device(self, context): if cscene.device == 'CPU' and engine.with_osl(): 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(): return [ bpy.types.RENDER_PT_render, @@ -514,12 +525,14 @@ def get_panels(): def register(): bpy.types.RENDER_PT_render.append(draw_device) + bpy.types.VIEW3D_HT_header.append(draw_pause) for panel in get_panels(): panel.COMPAT_ENGINES.add('CYCLES') def unregister(): bpy.types.RENDER_PT_render.remove(draw_device) + bpy.types.VIEW3D_HT_header.remove(draw_pause) for panel in get_panels(): panel.COMPAT_ENGINES.remove('CYCLES') diff --git a/intern/cycles/blender/blender_session.cpp b/intern/cycles/blender/blender_session.cpp index 7be15ca0e3c..62721b7cf10 100644 --- a/intern/cycles/blender/blender_session.cpp +++ b/intern/cycles/blender/blender_session.cpp @@ -93,6 +93,7 @@ void BlenderSession::create_session() session->scene = scene; session->progress.set_update_callback(function_bind(&BlenderSession::tag_redraw, this)); session->progress.set_cancel_callback(function_bind(&BlenderSession::test_cancel, this)); + session->set_pause(BlenderSync::get_session_pause(b_scene, background)); /* start rendering */ session->reset(width, height, session_params.passes); @@ -159,6 +160,7 @@ void BlenderSession::synchronize() /* increase passes, but never decrease */ 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 synchronization at a later time to not block on running updates */ @@ -178,12 +180,12 @@ void BlenderSession::synchronize() else sync->sync_camera(width, height); + /* unlock */ + session->scene->mutex.unlock(); + /* reset if needed */ if(scene->need_reset()) session->reset(width, height, session_params.passes); - - /* unlock */ - session->scene->mutex.unlock(); } bool BlenderSession::draw(int w, int h) diff --git a/intern/cycles/blender/blender_sync.cpp b/intern/cycles/blender/blender_sync.cpp index ccfc3bb2bf1..c579253336f 100644 --- a/intern/cycles/blender/blender_sync.cpp +++ b/intern/cycles/blender/blender_sync.cpp @@ -185,6 +185,12 @@ SceneParams BlenderSync::get_scene_params(BL::Scene b_scene) /* 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 params; diff --git a/intern/cycles/blender/blender_sync.h b/intern/cycles/blender/blender_sync.h index 16ce1998a24..fe60f42bc75 100644 --- a/intern/cycles/blender/blender_sync.h +++ b/intern/cycles/blender/blender_sync.h @@ -61,6 +61,7 @@ public: /* get parameters */ static SceneParams get_scene_params(BL::Scene b_scene); static SessionParams get_session_params(BL::Scene b_scene, bool background); + static bool get_session_pause(BL::Scene b_scene, bool background); private: /* sync */ diff --git a/intern/cycles/render/scene.cpp b/intern/cycles/render/scene.cpp index 85a0cc3a7c4..0b2e2b8a9b6 100644 --- a/intern/cycles/render/scene.cpp +++ b/intern/cycles/render/scene.cpp @@ -57,31 +57,31 @@ Scene::Scene(const SceneParams& params_) Scene::~Scene() { - camera->device_free(device, &dscene); + if(device) camera->device_free(device, &dscene); delete camera; - filter->device_free(device, &dscene); + if(device) filter->device_free(device, &dscene); delete filter; - film->device_free(device, &dscene); + if(device) film->device_free(device, &dscene); delete film; - background->device_free(device, &dscene); + if(device) background->device_free(device, &dscene); delete background; - mesh_manager->device_free(device, &dscene); + if(device) mesh_manager->device_free(device, &dscene); delete mesh_manager; - object_manager->device_free(device, &dscene); + if(device) object_manager->device_free(device, &dscene); delete object_manager; - integrator->device_free(device, &dscene); + if(device) integrator->device_free(device, &dscene); delete integrator; - shader_manager->device_free(device, &dscene); + if(device) shader_manager->device_free(device, &dscene); delete shader_manager; - light_manager->device_free(device, &dscene); + if(device) light_manager->device_free(device, &dscene); delete light_manager; foreach(Shader *s, shaders) @@ -93,7 +93,7 @@ Scene::~Scene() foreach(Light *l, lights) delete l; - image_manager->device_free(device, &dscene); + if(device) image_manager->device_free(device, &dscene); delete image_manager; } diff --git a/intern/cycles/render/session.cpp b/intern/cycles/render/session.cpp index 5465ddac06b..52366f06337 100644 --- a/intern/cycles/render/session.cpp +++ b/intern/cycles/render/session.cpp @@ -47,6 +47,7 @@ Session::Session(const SessionParams& params_) start_time = 0.0; reset_time = 0.0; preview_time = 0.0; + paused_time = 0.0; pass = 0; delayed_reset.do_reset = false; @@ -64,9 +65,16 @@ Session::~Session() { if(session_thread) { progress.set_cancel("Exiting"); + gpu_need_tonemap = false; gpu_need_tonemap_cond.notify_all(); - set_pause(false); + + { + thread_scoped_lock pause_lock(pause_mutex); + pause = false; + } + pause_cond.notify_all(); + wait(); } @@ -152,40 +160,54 @@ void Session::run_gpu() { start_time = time_dt(); reset_time = time_dt(); + paused_time = 0.0; while(!progress.get_cancel()) { /* 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; - } - else { - /* in interactive mode, we wait until woken up */ - thread_scoped_lock pause_lock(pause_mutex); - pause_cond.wait(pause_lock); - } } else { - /* test for pause and 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); - while(pause) - pause_cond.wait(pause_lock); - } - { - /* 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); + if(pause || no_tiles) { + update_status_time(pause, no_tiles); + while(1) { + double pause_start = time_dt(); + pause_cond.wait(pause_lock); + paused_time += time_dt() - pause_start; + + update_status_time(pause, no_tiles); + progress.set_update(); + + if(!pause) + break; + } + } + + if(progress.get_cancel()) + break; + } + + if(!no_tiles) { /* update scene */ update_scene(); if(progress.get_cancel()) 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_time(); @@ -276,29 +298,40 @@ void Session::run_cpu() while(!progress.get_cancel()) { /* advance to next tile */ - bool done = !tile_manager.next(); + bool no_tiles = !tile_manager.next(); 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; - } - else { - /* in interactive mode, we wait until woken up */ - thread_scoped_lock pause_lock(pause_mutex); - pause_cond.wait(pause_lock); - } } else { - /* test for pause and 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); - while(pause) - pause_cond.wait(pause_lock); + + if(pause || no_tiles) { + update_status_time(pause, no_tiles); + + while(1) { + double pause_start = time_dt(); + pause_cond.wait(pause_lock); + paused_time += time_dt() - pause_start; + + update_status_time(pause, no_tiles); + progress.set_update(); + + if(!pause) + break; + } + } + + if(progress.get_cancel()) + break; } - if(!done) { + 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 */ @@ -350,12 +383,6 @@ void Session::run() /* session thread loop */ 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 */ if(!progress.get_cancel()) { if(device_use_gl) @@ -391,6 +418,7 @@ void Session::reset_(int w, int h, int passes) start_time = time_dt(); preview_time = 0.0; + paused_time = 0.0; pass = 0; } @@ -408,18 +436,28 @@ void Session::set_passes(int passes) params.passes = passes; tile_manager.set_passes(passes); + { + thread_scoped_lock pause_lock(pause_mutex); + } pause_cond.notify_all(); } } void Session::set_pause(bool pause_) { + bool notify = false; + { thread_scoped_lock pause_lock(pause_mutex); - pause = pause_; + + if(pause != pause_) { + pause = pause_; + notify = true; + } } - pause_cond.notify_all(); + if(notify) + pause_cond.notify_all(); } void Session::wait() @@ -452,27 +490,40 @@ void Session::update_scene() 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 resolution = tile_manager.state.resolution; /* update status */ - string substatus; + string status, substatus; + if(!params.progressive) substatus = "Path Tracing"; else if(params.passes == INT_MAX) substatus = string_printf("Path Tracing Pass %d", pass+1); else 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 */ if(preview_time == 0.0 && resolution == 1) preview_time = time_dt(); - double total_time = (time_dt() - start_time); - double pass_time = (pass == 0)? 0.0: (time_dt() - preview_time)/(pass); + double total_time = time_dt() - start_time - paused_time; + 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); } diff --git a/intern/cycles/render/session.h b/intern/cycles/render/session.h index 3aaaeedf0c5..4d5cf434098 100644 --- a/intern/cycles/render/session.h +++ b/intern/cycles/render/session.h @@ -122,7 +122,7 @@ protected: void run(); void update_scene(); - void update_status_time(); + void update_status_time(bool show_pause = false, bool show_done = false); void tonemap(); void path_trace(Tile& tile); @@ -154,6 +154,7 @@ protected: double start_time; double reset_time; double preview_time; + double paused_time; }; CCL_NAMESPACE_END -- cgit v1.2.3