diff options
Diffstat (limited to 'intern/cycles/blender/blender_session.cpp')
-rw-r--r-- | intern/cycles/blender/blender_session.cpp | 316 |
1 files changed, 316 insertions, 0 deletions
diff --git a/intern/cycles/blender/blender_session.cpp b/intern/cycles/blender/blender_session.cpp new file mode 100644 index 00000000000..4433b1e24f9 --- /dev/null +++ b/intern/cycles/blender/blender_session.cpp @@ -0,0 +1,316 @@ +/* + * Copyright 2011, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "background.h" +#include "buffers.h" +#include "camera.h" +#include "device.h" +#include "integrator.h" +#include "film.h" +#include "light.h" +#include "scene.h" +#include "session.h" +#include "shader.h" + +#include "util_color.h" +#include "util_foreach.h" +#include "util_function.h" +#include "util_progress.h" +#include "util_time.h" + +#include "blender_sync.h" +#include "blender_session.h" +#include "blender_util.h" + +CCL_NAMESPACE_BEGIN + +BlenderSession::BlenderSession(BL::RenderEngine b_engine_, BL::BlendData b_data_, BL::Scene b_scene_) +: b_engine(b_engine_), b_data(b_data_), b_scene(b_scene_), b_v3d(PointerRNA_NULL), b_rv3d(PointerRNA_NULL) +{ + /* offline render */ + BL::RenderSettings r = b_scene.render(); + + width = (int)(r.resolution_x()*r.resolution_percentage()*0.01f); + height = (int)(r.resolution_y()*r.resolution_percentage()*0.01f); + background = true; + last_redraw_time = 0.0f; + + create_session(); +} + +BlenderSession::BlenderSession(BL::RenderEngine b_engine_, BL::BlendData b_data_, BL::Scene b_scene_, + BL::SpaceView3D b_v3d_, BL::RegionView3D b_rv3d_, int width_, int height_) +: b_engine(b_engine_), b_data(b_data_), b_scene(b_scene_), b_v3d(b_v3d_), b_rv3d(b_rv3d_) +{ + /* 3d view render */ + width = width_; + height = height_; + background = false; + last_redraw_time = 0.0f; + + create_session(); +} + +BlenderSession::~BlenderSession() +{ + free_session(); +} + +void BlenderSession::create_session() +{ + SceneParams scene_params = BlenderSync::get_scene_params(b_scene, background); + SessionParams session_params = BlenderSync::get_session_params(b_scene, background); + + /* reset status/progress */ + last_status= ""; + last_progress= -1.0f; + + /* create scene */ + scene = new Scene(scene_params); + + /* create sync */ + sync = new BlenderSync(b_data, b_scene, scene, !background); + sync->sync_data(b_v3d); + + if(b_rv3d) + sync->sync_view(b_v3d, b_rv3d, width, height); + else + sync->sync_camera(width, height); + + /* create session */ + session = new Session(session_params); + 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.samples); + session->start(); +} + +void BlenderSession::free_session() +{ + delete sync; + delete session; +} + +void BlenderSession::render() +{ + session->wait(); + + if(session->progress.get_cancel()) + return; + + /* write result */ + write_render_result(); +} + +void BlenderSession::write_render_result() +{ + /* get result */ + RenderBuffers *buffers = session->buffers; + float exposure = scene->film->exposure; + double total_time, sample_time; + int sample; + session->progress.get_sample(sample, total_time, sample_time); + + float4 *pixels = buffers->copy_from_device(exposure, sample); + + if(!pixels) + return; + + struct RenderResult *rrp = RE_engine_begin_result((RenderEngine*)b_engine.ptr.data, 0, 0, width, height); + PointerRNA rrptr; + RNA_pointer_create(NULL, &RNA_RenderResult, rrp, &rrptr); + BL::RenderResult rr(rrptr); + + BL::RenderResult::layers_iterator layer; + rr.layers.begin(layer); + rna_RenderLayer_rect_set(&layer->ptr, (float*)pixels); + + RE_engine_end_result((RenderEngine*)b_engine.ptr.data, rrp); + + delete [] pixels; +} + +void BlenderSession::synchronize() +{ + /* on session/scene parameter changes, we recreate session entirely */ + SceneParams scene_params = BlenderSync::get_scene_params(b_scene, background); + SessionParams session_params = BlenderSync::get_session_params(b_scene, background); + + if(session->params.modified(session_params) || + scene->params.modified(scene_params)) { + free_session(); + create_session(); + return; + } + + /* increase samples, but never decrease */ + session->set_samples(session_params.samples); + 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 */ + sync->sync_recalc(); + + /* try to acquire mutex. if we don't want to or can't, come back later */ + if(!session->ready_to_reset() || !session->scene->mutex.try_lock()) { + tag_update(); + return; + } + + /* data and camera synchronize */ + sync->sync_data(b_v3d); + + if(b_rv3d) + sync->sync_view(b_v3d, b_rv3d, width, height); + else + sync->sync_camera(width, height); + + /* unlock */ + session->scene->mutex.unlock(); + + /* reset if needed */ + if(scene->need_reset()) + session->reset(width, height, session_params.samples); +} + +bool BlenderSession::draw(int w, int h) +{ + /* before drawing, we verify camera and viewport size changes, because + we do not get update callbacks for those, we must detect them here */ + if(session->ready_to_reset()) { + bool reset = false; + + /* try to acquire mutex. if we can't, come back later */ + if(!session->scene->mutex.try_lock()) { + tag_update(); + } + else { + /* update camera from 3d view */ + bool need_update = scene->camera->need_update; + + sync->sync_view(b_v3d, b_rv3d, w, h); + + if(scene->camera->need_update && !need_update) + reset = true; + + session->scene->mutex.unlock(); + } + + /* if dimensions changed, reset */ + if(width != w || height != h) { + width = w; + height = h; + reset = true; + } + + /* reset if requested */ + if(reset) { + SessionParams session_params = BlenderSync::get_session_params(b_scene, background); + session->reset(width, height, session_params.samples); + } + } + + /* update status and progress for 3d view draw */ + update_status_progress(); + + /* draw */ + return !session->draw(width, height); +} + +void BlenderSession::get_status(string& status, string& substatus) +{ + session->progress.get_status(status, substatus); +} + +void BlenderSession::get_progress(float& progress, double& total_time) +{ + double sample_time; + int sample; + + session->progress.get_sample(sample, total_time, sample_time); + progress = ((float)sample/(float)session->params.samples); +} + +void BlenderSession::update_status_progress() +{ + string status, substatus; + float progress; + double total_time; + char time_str[128]; + + get_status(status, substatus); + get_progress(progress, total_time); + + if(!background) { + BLI_timestr(total_time, time_str); + status = "Time: " + string(time_str) + " | " + status; + } + + if(substatus.size() > 0) + status += " | " + substatus; + + if(status != last_status) { + RE_engine_update_stats((RenderEngine*)b_engine.ptr.data, "", status.c_str()); + last_status = status; + } + if(progress != last_progress) { + RE_engine_update_progress((RenderEngine*)b_engine.ptr.data, progress); + last_progress = progress; + } +} + +void BlenderSession::tag_update() +{ + /* tell blender that we want to get another update callback */ + engine_tag_update((RenderEngine*)b_engine.ptr.data); +} + +void BlenderSession::tag_redraw() +{ + if(background) { + /* update stats and progress, only for background here because + in 3d view we do it in draw for thread safety reasons */ + update_status_progress(); + + /* offline render, redraw if timeout passed */ + if(time_dt() - last_redraw_time > 1.0f) { + write_render_result(); + engine_tag_redraw((RenderEngine*)b_engine.ptr.data); + last_redraw_time = time_dt(); + } + } + else { + /* tell blender that we want to redraw */ + engine_tag_redraw((RenderEngine*)b_engine.ptr.data); + } +} + +void BlenderSession::test_cancel() +{ + /* test if we need to cancel rendering */ + if(background) + if(RE_engine_test_break((RenderEngine*)b_engine.ptr.data)) + session->progress.set_cancel("Cancelled"); +} + +CCL_NAMESPACE_END + |