Blender V2.61 - r43446

blender_session.cpp

Go to the documentation of this file.
00001 /*
00002  * Copyright 2011, Blender Foundation.
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  */
00018 
00019 #include "background.h"
00020 #include "buffers.h"
00021 #include "camera.h"
00022 #include "device.h"
00023 #include "integrator.h"
00024 #include "film.h"
00025 #include "light.h"
00026 #include "scene.h"
00027 #include "session.h"
00028 #include "shader.h"
00029 
00030 #include "util_color.h"
00031 #include "util_foreach.h"
00032 #include "util_function.h"
00033 #include "util_progress.h"
00034 #include "util_time.h"
00035 
00036 #include "blender_sync.h"
00037 #include "blender_session.h"
00038 #include "blender_util.h"
00039 
00040 CCL_NAMESPACE_BEGIN
00041 
00042 BlenderSession::BlenderSession(BL::RenderEngine b_engine_, BL::UserPreferences b_userpref_,
00043     BL::BlendData b_data_, BL::Scene b_scene_)
00044 : b_engine(b_engine_), b_userpref(b_userpref_), b_data(b_data_), b_scene(b_scene_),
00045   b_v3d(PointerRNA_NULL), b_rv3d(PointerRNA_NULL),
00046   b_rr(PointerRNA_NULL), b_rlay(PointerRNA_NULL)
00047 {
00048     /* offline render */
00049     BL::RenderSettings r = b_scene.render();
00050 
00051     width = (int)(r.resolution_x()*r.resolution_percentage()/100);
00052     height = (int)(r.resolution_y()*r.resolution_percentage()/100);
00053     background = true;
00054     last_redraw_time = 0.0f;
00055 
00056     create_session();
00057 }
00058 
00059 BlenderSession::BlenderSession(BL::RenderEngine b_engine_, BL::UserPreferences b_userpref_,
00060     BL::BlendData b_data_, BL::Scene b_scene_,
00061     BL::SpaceView3D b_v3d_, BL::RegionView3D b_rv3d_, int width_, int height_)
00062 : b_engine(b_engine_), b_userpref(b_userpref_), b_data(b_data_), b_scene(b_scene_),
00063   b_v3d(b_v3d_), b_rv3d(b_rv3d_), b_rr(PointerRNA_NULL), b_rlay(PointerRNA_NULL)
00064 {
00065     /* 3d view render */
00066     width = width_;
00067     height = height_;
00068     background = false;
00069     last_redraw_time = 0.0f;
00070 
00071     create_session();
00072     session->start();
00073 }
00074 
00075 BlenderSession::~BlenderSession()
00076 {
00077     free_session();
00078 }
00079 
00080 void BlenderSession::create_session()
00081 {
00082     SceneParams scene_params = BlenderSync::get_scene_params(b_scene, background);
00083     SessionParams session_params = BlenderSync::get_session_params(b_userpref, b_scene, background);
00084 
00085     /* reset status/progress */
00086     last_status= "";
00087     last_progress= -1.0f;
00088 
00089     /* create scene */
00090     scene = new Scene(scene_params);
00091 
00092     /* create sync */
00093     sync = new BlenderSync(b_data, b_scene, scene, !background);
00094     sync->sync_data(b_v3d);
00095 
00096     if(b_rv3d)
00097         sync->sync_view(b_v3d, b_rv3d, width, height);
00098     else
00099         sync->sync_camera(width, height);
00100 
00101     /* create session */
00102     session = new Session(session_params);
00103     session->scene = scene;
00104     session->progress.set_update_callback(function_bind(&BlenderSession::tag_redraw, this));
00105     session->progress.set_cancel_callback(function_bind(&BlenderSession::test_cancel, this));
00106     session->set_pause(BlenderSync::get_session_pause(b_scene, background));
00107 
00108     /* set buffer parameters */
00109     BufferParams buffer_params = BlenderSync::get_buffer_params(b_scene, b_rv3d, width, height);
00110     session->reset(buffer_params, session_params.samples);
00111 }
00112 
00113 void BlenderSession::free_session()
00114 {
00115     delete sync;
00116     delete session;
00117 }
00118 
00119 void BlenderSession::render()
00120 {
00121     /* get buffer parameters */
00122     BufferParams buffer_params = BlenderSync::get_buffer_params(b_scene, b_rv3d, width, height);
00123     int w = buffer_params.width, h = buffer_params.height;
00124 
00125     /* create render result */
00126     RenderResult *rrp = RE_engine_begin_result((RenderEngine*)b_engine.ptr.data, 0, 0, w, h);
00127     PointerRNA rrptr;
00128     RNA_pointer_create(NULL, &RNA_RenderResult, rrp, &rrptr);
00129     b_rr = BL::RenderResult(rrptr);
00130 
00131     BL::RenderSettings r = b_scene.render();
00132     BL::RenderResult::layers_iterator b_iter;
00133     BL::RenderLayers b_rr_layers(r.ptr);
00134     
00135     int active = 0;
00136 
00137     /* render each layer */
00138     for(b_rr.layers.begin(b_iter); b_iter != b_rr.layers.end(); ++b_iter, ++active) {
00139         /* single layer render */
00140         if(r.use_single_layer())
00141             active = b_rr_layers.active_index();
00142 
00143         /* set layer */
00144         b_rlay = *b_iter;
00145 
00146         /* update scene */
00147         sync->sync_data(b_v3d, active);
00148 
00149         /* render */
00150         session->start();
00151         session->wait();
00152 
00153         if(session->progress.get_cancel())
00154             break;
00155 
00156         /* write result */
00157         write_render_result();
00158     }
00159 
00160     /* delete render result */
00161     RE_engine_end_result((RenderEngine*)b_engine.ptr.data, (RenderResult*)b_rr.ptr.data);
00162 }
00163 
00164 void BlenderSession::write_render_result()
00165 {
00166     /* get state */
00167     RenderBuffers *buffers = session->buffers;
00168     float exposure = scene->film->exposure;
00169     double total_time, sample_time;
00170     int sample;
00171     session->progress.get_sample(sample, total_time, sample_time);
00172 
00173     /* get pixels */
00174     float4 *pixels = buffers->copy_from_device(exposure, sample);
00175 
00176     if(!pixels)
00177         return;
00178 
00179     /* write pixels */
00180     rna_RenderLayer_rect_set(&b_rlay.ptr, (float*)pixels);
00181     RE_engine_update_result((RenderEngine*)b_engine.ptr.data, (RenderResult*)b_rr.ptr.data);
00182 
00183     delete [] pixels;
00184 }
00185 
00186 void BlenderSession::synchronize()
00187 {
00188     /* on session/scene parameter changes, we recreate session entirely */
00189     SceneParams scene_params = BlenderSync::get_scene_params(b_scene, background);
00190     SessionParams session_params = BlenderSync::get_session_params(b_userpref, b_scene, background);
00191 
00192     if(session->params.modified(session_params) ||
00193        scene->params.modified(scene_params)) {
00194         free_session();
00195         create_session();
00196         session->start();
00197         return;
00198     }
00199 
00200     /* increase samples, but never decrease */
00201     session->set_samples(session_params.samples);
00202     session->set_pause(BlenderSync::get_session_pause(b_scene, background));
00203 
00204     /* copy recalc flags, outside of mutex so we can decide to do the real
00205        synchronization at a later time to not block on running updates */
00206     sync->sync_recalc();
00207 
00208     /* try to acquire mutex. if we don't want to or can't, come back later */
00209     if(!session->ready_to_reset() || !session->scene->mutex.try_lock()) {
00210         tag_update();
00211         return;
00212     }
00213 
00214     /* data and camera synchronize */
00215     sync->sync_data(b_v3d);
00216 
00217     if(b_rv3d)
00218         sync->sync_view(b_v3d, b_rv3d, width, height);
00219     else
00220         sync->sync_camera(width, height);
00221 
00222     /* unlock */
00223     session->scene->mutex.unlock();
00224 
00225     /* reset if needed */
00226     if(scene->need_reset()) {
00227         BufferParams buffer_params = BlenderSync::get_buffer_params(b_scene, b_rv3d, width, height);
00228         session->reset(buffer_params, session_params.samples);
00229     }
00230 }
00231 
00232 bool BlenderSession::draw(int w, int h)
00233 {
00234     /* before drawing, we verify camera and viewport size changes, because
00235        we do not get update callbacks for those, we must detect them here */
00236     if(session->ready_to_reset()) {
00237         bool reset = false;
00238 
00239         /* try to acquire mutex. if we can't, come back later */
00240         if(!session->scene->mutex.try_lock()) {
00241             tag_update();
00242         }
00243         else {
00244             /* update camera from 3d view */
00245             bool need_update = scene->camera->need_update;
00246 
00247             sync->sync_view(b_v3d, b_rv3d, w, h);
00248 
00249             if(scene->camera->need_update && !need_update)
00250                 reset = true;
00251 
00252             session->scene->mutex.unlock();
00253         }
00254 
00255         /* if dimensions changed, reset */
00256         if(width != w || height != h) {
00257             width = w;
00258             height = h;
00259             reset = true;
00260         }
00261 
00262         /* reset if requested */
00263         if(reset) {
00264             SessionParams session_params = BlenderSync::get_session_params(b_userpref, b_scene, background);
00265             BufferParams buffer_params = BlenderSync::get_buffer_params(b_scene, b_rv3d, width, height);
00266 
00267             session->reset(buffer_params, session_params.samples);
00268         }
00269     }
00270 
00271     /* update status and progress for 3d view draw */
00272     update_status_progress();
00273 
00274     /* draw */
00275     BufferParams buffer_params = BlenderSync::get_buffer_params(b_scene, b_rv3d, width, height);
00276 
00277     return !session->draw(buffer_params);
00278 }
00279 
00280 void BlenderSession::get_status(string& status, string& substatus)
00281 {
00282     session->progress.get_status(status, substatus);
00283 }
00284 
00285 void BlenderSession::get_progress(float& progress, double& total_time)
00286 {
00287     double sample_time;
00288     int sample;
00289 
00290     session->progress.get_sample(sample, total_time, sample_time);
00291     progress = ((float)sample/(float)session->params.samples);
00292 }
00293 
00294 void BlenderSession::update_status_progress()
00295 {
00296     string status, substatus;
00297     float progress;
00298     double total_time;
00299     char time_str[128];
00300 
00301     get_status(status, substatus);
00302     get_progress(progress, total_time);
00303 
00304     BLI_timestr(total_time, time_str);
00305     status = "Elapsed: " + string(time_str) + " | " + status;
00306 
00307     if(substatus.size() > 0)
00308         status += " | " + substatus;
00309 
00310     if(status != last_status) {
00311         RE_engine_update_stats((RenderEngine*)b_engine.ptr.data, "", status.c_str());
00312         last_status = status;
00313     }
00314     if(progress != last_progress) {
00315         RE_engine_update_progress((RenderEngine*)b_engine.ptr.data, progress);
00316         last_progress = progress;
00317     }
00318 }
00319 
00320 void BlenderSession::tag_update()
00321 {
00322     /* tell blender that we want to get another update callback */
00323     engine_tag_update((RenderEngine*)b_engine.ptr.data);
00324 }
00325 
00326 void BlenderSession::tag_redraw()
00327 {
00328     if(background) {
00329         /* update stats and progress, only for background here because
00330            in 3d view we do it in draw for thread safety reasons */
00331         update_status_progress();
00332 
00333         /* offline render, redraw if timeout passed */
00334         if(time_dt() - last_redraw_time > 1.0f) {
00335             write_render_result();
00336             engine_tag_redraw((RenderEngine*)b_engine.ptr.data);
00337             last_redraw_time = time_dt();
00338         }
00339     }
00340     else {
00341         /* tell blender that we want to redraw */
00342         engine_tag_redraw((RenderEngine*)b_engine.ptr.data);
00343     }
00344 }
00345 
00346 void BlenderSession::test_cancel()
00347 {
00348     /* test if we need to cancel rendering */
00349     if(background)
00350         if(RE_engine_test_break((RenderEngine*)b_engine.ptr.data))
00351             session->progress.set_cancel("Cancelled");
00352 }
00353 
00354 CCL_NAMESPACE_END
00355