Sequencer: invalidate current frame cache on sequence transform
[blender.git] / intern / cycles / blender / blender_session.cpp
1 /*
2  * Copyright 2011, Blender Foundation.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  */
18
19 #include "background.h"
20 #include "buffers.h"
21 #include "camera.h"
22 #include "device.h"
23 #include "integrator.h"
24 #include "film.h"
25 #include "light.h"
26 #include "scene.h"
27 #include "session.h"
28 #include "shader.h"
29
30 #include "util_color.h"
31 #include "util_foreach.h"
32 #include "util_function.h"
33 #include "util_progress.h"
34 #include "util_time.h"
35
36 #include "blender_sync.h"
37 #include "blender_session.h"
38 #include "blender_util.h"
39
40 CCL_NAMESPACE_BEGIN
41
42 BlenderSession::BlenderSession(BL::RenderEngine b_engine_, BL::UserPreferences b_userpref_,
43         BL::BlendData b_data_, BL::Scene b_scene_)
44 : b_engine(b_engine_), b_userpref(b_userpref_), b_data(b_data_), b_scene(b_scene_),
45   b_v3d(PointerRNA_NULL), b_rv3d(PointerRNA_NULL),
46   b_rr(PointerRNA_NULL), b_rlay(PointerRNA_NULL)
47 {
48         /* offline render */
49         BL::RenderSettings r = b_scene.render();
50
51         width = (int)(r.resolution_x()*r.resolution_percentage()/100);
52         height = (int)(r.resolution_y()*r.resolution_percentage()/100);
53         background = true;
54         last_redraw_time = 0.0f;
55
56         create_session();
57 }
58
59 BlenderSession::BlenderSession(BL::RenderEngine b_engine_, BL::UserPreferences b_userpref_,
60         BL::BlendData b_data_, BL::Scene b_scene_,
61         BL::SpaceView3D b_v3d_, BL::RegionView3D b_rv3d_, int width_, int height_)
62 : b_engine(b_engine_), b_userpref(b_userpref_), b_data(b_data_), b_scene(b_scene_),
63   b_v3d(b_v3d_), b_rv3d(b_rv3d_), b_rr(PointerRNA_NULL), b_rlay(PointerRNA_NULL)
64 {
65         /* 3d view render */
66         width = width_;
67         height = height_;
68         background = false;
69         last_redraw_time = 0.0f;
70
71         create_session();
72         session->start();
73 }
74
75 BlenderSession::~BlenderSession()
76 {
77         free_session();
78 }
79
80 void BlenderSession::create_session()
81 {
82         SceneParams scene_params = BlenderSync::get_scene_params(b_scene, background);
83         SessionParams session_params = BlenderSync::get_session_params(b_userpref, b_scene, background);
84
85         /* reset status/progress */
86         last_status = "";
87         last_progress = -1.0f;
88
89         /* create scene */
90         scene = new Scene(scene_params);
91
92         /* create sync */
93         sync = new BlenderSync(b_data, b_scene, scene, !background);
94         sync->sync_data(b_v3d, b_engine.camera_override());
95
96         if(b_rv3d)
97                 sync->sync_view(b_v3d, b_rv3d, width, height);
98         else
99                 sync->sync_camera(b_engine.camera_override(), width, height);
100
101         /* create session */
102         session = new Session(session_params);
103         session->scene = scene;
104         session->progress.set_update_callback(function_bind(&BlenderSession::tag_redraw, this));
105         session->progress.set_cancel_callback(function_bind(&BlenderSession::test_cancel, this));
106         session->set_pause(BlenderSync::get_session_pause(b_scene, background));
107
108         /* set buffer parameters */
109         BufferParams buffer_params = BlenderSync::get_buffer_params(b_scene, scene->camera, width, height);
110         session->reset(buffer_params, session_params.samples);
111 }
112
113 void BlenderSession::free_session()
114 {
115         delete sync;
116         delete session;
117 }
118
119 static PassType get_pass_type(BL::RenderPass b_pass)
120 {
121         switch(b_pass.type()) {
122                 case BL::RenderPass::type_COMBINED:
123                         return PASS_COMBINED;
124
125                 case BL::RenderPass::type_Z:
126                         return PASS_DEPTH;
127                 case BL::RenderPass::type_NORMAL:
128                         return PASS_NORMAL;
129                 case BL::RenderPass::type_OBJECT_INDEX:
130                         return PASS_OBJECT_ID;
131                 case BL::RenderPass::type_UV:
132                         return PASS_UV;
133                 case BL::RenderPass::type_VECTOR:
134                         return PASS_MOTION;
135                 case BL::RenderPass::type_MATERIAL_INDEX:
136                         return PASS_MATERIAL_ID;
137
138                 case BL::RenderPass::type_DIFFUSE_DIRECT:
139                         return PASS_DIFFUSE_DIRECT;
140                 case BL::RenderPass::type_GLOSSY_DIRECT:
141                         return PASS_GLOSSY_DIRECT;
142                 case BL::RenderPass::type_TRANSMISSION_DIRECT:
143                         return PASS_TRANSMISSION_DIRECT;
144
145                 case BL::RenderPass::type_DIFFUSE_INDIRECT:
146                         return PASS_DIFFUSE_INDIRECT;
147                 case BL::RenderPass::type_GLOSSY_INDIRECT:
148                         return PASS_GLOSSY_INDIRECT;
149                 case BL::RenderPass::type_TRANSMISSION_INDIRECT:
150                         return PASS_TRANSMISSION_INDIRECT;
151
152                 case BL::RenderPass::type_DIFFUSE_COLOR:
153                         return PASS_DIFFUSE_COLOR;
154                 case BL::RenderPass::type_GLOSSY_COLOR:
155                         return PASS_GLOSSY_COLOR;
156                 case BL::RenderPass::type_TRANSMISSION_COLOR:
157                         return PASS_TRANSMISSION_COLOR;
158
159                 case BL::RenderPass::type_EMIT:
160                         return PASS_EMISSION;
161                 case BL::RenderPass::type_ENVIRONMENT:
162                         return PASS_BACKGROUND;
163                 case BL::RenderPass::type_AO:
164                         return PASS_AO;
165                 case BL::RenderPass::type_SHADOW:
166                         return PASS_SHADOW;
167
168                 case BL::RenderPass::type_DIFFUSE:
169                 case BL::RenderPass::type_COLOR:
170                 case BL::RenderPass::type_REFRACTION:
171                 case BL::RenderPass::type_SPECULAR:
172                 case BL::RenderPass::type_REFLECTION:
173                 case BL::RenderPass::type_MIST:
174                         return PASS_NONE;
175         }
176         
177         return PASS_NONE;
178 }
179
180 void BlenderSession::render()
181 {
182         /* get buffer parameters */
183         SessionParams session_params = BlenderSync::get_session_params(b_userpref, b_scene, background);
184         BufferParams buffer_params = BlenderSync::get_buffer_params(b_scene, scene->camera, width, height);
185         int w = buffer_params.width, h = buffer_params.height;
186
187         /* create render result */
188         RenderResult *rrp = RE_engine_begin_result((RenderEngine*)b_engine.ptr.data, 0, 0, w, h);
189         PointerRNA rrptr;
190         RNA_pointer_create(NULL, &RNA_RenderResult, rrp, &rrptr);
191         b_rr = BL::RenderResult(rrptr);
192
193         BL::RenderSettings r = b_scene.render();
194         BL::RenderResult::layers_iterator b_iter;
195         BL::RenderLayers b_rr_layers(r.ptr);
196         
197         /* render each layer */
198         for(b_rr.layers.begin(b_iter); b_iter != b_rr.layers.end(); ++b_iter) {
199                 /* set layer */
200                 b_rlay = *b_iter;
201
202                 /* add passes */
203                 vector<Pass> passes;
204                 Pass::add(PASS_COMBINED, passes);
205
206                 if(session_params.device.advanced_shading) {
207                         BL::RenderLayer::passes_iterator b_pass_iter;
208                         
209                         for(b_rlay.passes.begin(b_pass_iter); b_pass_iter != b_rlay.passes.end(); ++b_pass_iter) {
210                                 BL::RenderPass b_pass(*b_pass_iter);
211                                 PassType pass_type = get_pass_type(b_pass);
212
213                                 if(pass_type == PASS_MOTION && scene->integrator->motion_blur)
214                                         continue;
215                                 if(pass_type != PASS_NONE)
216                                         Pass::add(pass_type, passes);
217                         }
218                 }
219
220                 buffer_params.passes = passes;
221                 scene->film->tag_passes_update(scene, passes);
222                 scene->film->tag_update(scene);
223                 scene->integrator->tag_update(scene);
224
225                 /* update scene */
226                 sync->sync_data(b_v3d, b_engine.camera_override(), b_iter->name().c_str());
227
228                 /* update session */
229                 int samples = sync->get_layer_samples();
230                 session->reset(buffer_params, (samples == 0)? session_params.samples: samples);
231
232                 /* render */
233                 session->start();
234                 session->wait();
235
236                 if(session->progress.get_cancel())
237                         break;
238
239                 /* write result */
240                 write_render_result();
241         }
242
243         /* delete render result */
244         RE_engine_end_result((RenderEngine*)b_engine.ptr.data, (RenderResult*)b_rr.ptr.data);
245 }
246
247 void BlenderSession::write_render_result()
248 {
249         /* get state */
250         RenderBuffers *buffers = session->buffers;
251
252         /* copy data from device */
253         if(!buffers->copy_from_device())
254                 return;
255
256         BufferParams& params = buffers->params;
257         float exposure = scene->film->exposure;
258         double total_time, sample_time;
259         int sample;
260
261         session->progress.get_sample(sample, total_time, sample_time);
262
263         vector<float> pixels(params.width*params.height*4);
264
265         /* copy each pass */
266         BL::RenderLayer::passes_iterator b_iter;
267         
268         for(b_rlay.passes.begin(b_iter); b_iter != b_rlay.passes.end(); ++b_iter) {
269                 BL::RenderPass b_pass(*b_iter);
270
271                 /* find matching pass type */
272                 PassType pass_type = get_pass_type(b_pass);
273                 int components = b_pass.channels();
274
275                 /* copy pixels */
276                 if(buffers->get_pass(pass_type, exposure, sample, components, &pixels[0]))
277                         rna_RenderPass_rect_set(&b_pass.ptr, &pixels[0]);
278         }
279
280         /* copy combined pass */
281         if(buffers->get_pass(PASS_COMBINED, exposure, sample, 4, &pixels[0]))
282                 rna_RenderLayer_rect_set(&b_rlay.ptr, &pixels[0]);
283
284         /* tag result as updated */
285         RE_engine_update_result((RenderEngine*)b_engine.ptr.data, (RenderResult*)b_rr.ptr.data);
286 }
287
288 void BlenderSession::synchronize()
289 {
290         /* on session/scene parameter changes, we recreate session entirely */
291         SceneParams scene_params = BlenderSync::get_scene_params(b_scene, background);
292         SessionParams session_params = BlenderSync::get_session_params(b_userpref, b_scene, background);
293
294         if(session->params.modified(session_params) ||
295            scene->params.modified(scene_params))
296         {
297                 free_session();
298                 create_session();
299                 session->start();
300                 return;
301         }
302
303         /* increase samples, but never decrease */
304         session->set_samples(session_params.samples);
305         session->set_pause(BlenderSync::get_session_pause(b_scene, background));
306
307         /* copy recalc flags, outside of mutex so we can decide to do the real
308          * synchronization at a later time to not block on running updates */
309         sync->sync_recalc();
310
311         /* try to acquire mutex. if we don't want to or can't, come back later */
312         if(!session->ready_to_reset() || !session->scene->mutex.try_lock()) {
313                 tag_update();
314                 return;
315         }
316
317         /* data and camera synchronize */
318         sync->sync_data(b_v3d, b_engine.camera_override());
319
320         if(b_rv3d)
321                 sync->sync_view(b_v3d, b_rv3d, width, height);
322         else
323                 sync->sync_camera(b_engine.camera_override(), width, height);
324
325         /* unlock */
326         session->scene->mutex.unlock();
327
328         /* reset if needed */
329         if(scene->need_reset()) {
330                 BufferParams buffer_params = BlenderSync::get_buffer_params(b_scene, scene->camera, width, height);
331                 session->reset(buffer_params, session_params.samples);
332         }
333 }
334
335 bool BlenderSession::draw(int w, int h)
336 {
337         /* before drawing, we verify camera and viewport size changes, because
338          * we do not get update callbacks for those, we must detect them here */
339         if(session->ready_to_reset()) {
340                 bool reset = false;
341
342                 /* try to acquire mutex. if we can't, come back later */
343                 if(!session->scene->mutex.try_lock()) {
344                         tag_update();
345                 }
346                 else {
347                         /* update camera from 3d view */
348                         bool need_update = scene->camera->need_update;
349
350                         sync->sync_view(b_v3d, b_rv3d, w, h);
351
352                         if(scene->camera->need_update && !need_update)
353                                 reset = true;
354
355                         session->scene->mutex.unlock();
356                 }
357
358                 /* if dimensions changed, reset */
359                 if(width != w || height != h) {
360                         width = w;
361                         height = h;
362                         reset = true;
363                 }
364
365                 /* reset if requested */
366                 if(reset) {
367                         SessionParams session_params = BlenderSync::get_session_params(b_userpref, b_scene, background);
368                         BufferParams buffer_params = BlenderSync::get_buffer_params(b_scene, scene->camera, w, h);
369
370                         session->reset(buffer_params, session_params.samples);
371                 }
372         }
373
374         /* update status and progress for 3d view draw */
375         update_status_progress();
376
377         /* draw */
378         BufferParams buffer_params = BlenderSync::get_buffer_params(b_scene, scene->camera, width, height);
379
380         return !session->draw(buffer_params);
381 }
382
383 void BlenderSession::get_status(string& status, string& substatus)
384 {
385         session->progress.get_status(status, substatus);
386 }
387
388 void BlenderSession::get_progress(float& progress, double& total_time)
389 {
390         double sample_time;
391         int sample;
392
393         session->progress.get_sample(sample, total_time, sample_time);
394         progress = ((float)sample/(float)session->params.samples);
395 }
396
397 void BlenderSession::update_status_progress()
398 {
399         string timestatus, status, substatus;
400         float progress;
401         double total_time;
402         char time_str[128];
403
404         get_status(status, substatus);
405         get_progress(progress, total_time);
406
407         BLI_timestr(total_time, time_str);
408         timestatus = "Elapsed: " + string(time_str) + " | ";
409
410         if(substatus.size() > 0)
411                 status += " | " + substatus;
412
413         if(status != last_status) {
414                 RE_engine_update_stats((RenderEngine*)b_engine.ptr.data, "", (timestatus + status).c_str());
415                 last_status = status;
416         }
417         if(progress != last_progress) {
418                 RE_engine_update_progress((RenderEngine*)b_engine.ptr.data, progress);
419                 last_progress = progress;
420         }
421 }
422
423 void BlenderSession::tag_update()
424 {
425         /* tell blender that we want to get another update callback */
426         engine_tag_update((RenderEngine*)b_engine.ptr.data);
427 }
428
429 void BlenderSession::tag_redraw()
430 {
431         if(background) {
432                 /* update stats and progress, only for background here because
433                  * in 3d view we do it in draw for thread safety reasons */
434                 update_status_progress();
435
436                 /* offline render, redraw if timeout passed */
437                 if(time_dt() - last_redraw_time > 1.0) {
438                         write_render_result();
439                         engine_tag_redraw((RenderEngine*)b_engine.ptr.data);
440                         last_redraw_time = time_dt();
441                 }
442         }
443         else {
444                 /* tell blender that we want to redraw */
445                 engine_tag_redraw((RenderEngine*)b_engine.ptr.data);
446         }
447 }
448
449 void BlenderSession::test_cancel()
450 {
451         /* test if we need to cancel rendering */
452         if(background)
453                 if(RE_engine_test_break((RenderEngine*)b_engine.ptr.data))
454                         session->progress.set_cancel("Cancelled");
455 }
456
457 CCL_NAMESPACE_END
458