Cycles: Implement camera zoom motion blur
[blender-staging.git] / intern / cycles / blender / blender_session.cpp
1 /*
2  * Copyright 2011-2013 Blender Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <stdlib.h>
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 "mesh.h"
27 #include "object.h"
28 #include "scene.h"
29 #include "session.h"
30 #include "shader.h"
31
32 #include "util_color.h"
33 #include "util_foreach.h"
34 #include "util_function.h"
35 #include "util_logging.h"
36 #include "util_progress.h"
37 #include "util_time.h"
38
39 #include "blender_sync.h"
40 #include "blender_session.h"
41 #include "blender_util.h"
42
43 CCL_NAMESPACE_BEGIN
44
45 bool BlenderSession::headless = false;
46
47 BlenderSession::BlenderSession(BL::RenderEngine b_engine_, BL::UserPreferences b_userpref_,
48         BL::BlendData b_data_, BL::Scene b_scene_)
49 : b_engine(b_engine_), b_userpref(b_userpref_), b_data(b_data_), b_render(b_engine_.render()), b_scene(b_scene_),
50   b_v3d(PointerRNA_NULL), b_rv3d(PointerRNA_NULL), python_thread_state(NULL)
51 {
52         /* offline render */
53
54         width = render_resolution_x(b_render);
55         height = render_resolution_y(b_render);
56
57         background = true;
58         last_redraw_time = 0.0;
59         start_resize_time = 0.0;
60 }
61
62 BlenderSession::BlenderSession(BL::RenderEngine b_engine_, BL::UserPreferences b_userpref_,
63         BL::BlendData b_data_, BL::Scene b_scene_,
64         BL::SpaceView3D b_v3d_, BL::RegionView3D b_rv3d_, int width_, int height_)
65 : b_engine(b_engine_), b_userpref(b_userpref_), b_data(b_data_), b_render(b_scene_.render()), b_scene(b_scene_),
66   b_v3d(b_v3d_), b_rv3d(b_rv3d_), python_thread_state(NULL)
67 {
68         /* 3d view render */
69
70         width = width_;
71         height = height_;
72         background = false;
73         last_redraw_time = 0.0;
74         start_resize_time = 0.0;
75 }
76
77 BlenderSession::~BlenderSession()
78 {
79         free_session();
80 }
81
82 void BlenderSession::create()
83 {
84         create_session();
85
86         if(b_v3d)
87                 session->start();
88 }
89
90 void BlenderSession::create_session()
91 {
92         SessionParams session_params = BlenderSync::get_session_params(b_engine, b_userpref, b_scene, background);
93         bool is_cpu = session_params.device.type == DEVICE_CPU;
94         SceneParams scene_params = BlenderSync::get_scene_params(b_scene, background, is_cpu);
95         bool session_pause = BlenderSync::get_session_pause(b_scene, background);
96
97         /* reset status/progress */
98         last_status = "";
99         last_error = "";
100         last_progress = -1.0f;
101         start_resize_time = 0.0;
102
103         /* create scene */
104         scene = new Scene(scene_params, session_params.device);
105
106         /* setup callbacks for builtin image support */
107         scene->image_manager->builtin_image_info_cb = function_bind(&BlenderSession::builtin_image_info, this, _1, _2, _3, _4, _5, _6, _7);
108         scene->image_manager->builtin_image_pixels_cb = function_bind(&BlenderSession::builtin_image_pixels, this, _1, _2, _3);
109         scene->image_manager->builtin_image_float_pixels_cb = function_bind(&BlenderSession::builtin_image_float_pixels, this, _1, _2, _3);
110
111         /* create session */
112         session = new Session(session_params);
113         session->scene = scene;
114         session->progress.set_update_callback(function_bind(&BlenderSession::tag_redraw, this));
115         session->progress.set_cancel_callback(function_bind(&BlenderSession::test_cancel, this));
116         session->set_pause(session_pause);
117
118         /* create sync */
119         sync = new BlenderSync(b_engine, b_data, b_scene, scene, !background, session->progress, is_cpu);
120
121         if(b_v3d) {
122                 if(session_pause == false) {
123                         /* full data sync */
124                         sync->sync_view(b_v3d, b_rv3d, width, height);
125                         sync->sync_data(b_render,
126                                         b_v3d,
127                                         b_engine.camera_override(),
128                                         width, height,
129                                         &python_thread_state,
130                                         b_rlay_name.c_str());
131                 }
132         }
133         else {
134                 /* for final render we will do full data sync per render layer, only
135                  * do some basic syncing here, no objects or materials for speed */
136                 sync->sync_render_layers(b_v3d, NULL);
137                 sync->sync_integrator();
138                 sync->sync_camera(b_render, b_engine.camera_override(), width, height);
139         }
140
141         /* set buffer parameters */
142         BufferParams buffer_params = BlenderSync::get_buffer_params(b_render, b_v3d, b_rv3d, scene->camera, width, height);
143         session->reset(buffer_params, session_params.samples);
144
145         b_engine.use_highlight_tiles(session_params.progressive_refine == false);
146 }
147
148 void BlenderSession::reset_session(BL::BlendData b_data_, BL::Scene b_scene_)
149 {
150         b_data = b_data_;
151         b_render = b_engine.render();
152         b_scene = b_scene_;
153
154         SessionParams session_params = BlenderSync::get_session_params(b_engine, b_userpref, b_scene, background);
155         const bool is_cpu = session_params.device.type == DEVICE_CPU;
156         SceneParams scene_params = BlenderSync::get_scene_params(b_scene, background, is_cpu);
157
158         width = render_resolution_x(b_render);
159         height = render_resolution_y(b_render);
160
161         if(scene->params.modified(scene_params) ||
162            session->params.modified(session_params) ||
163            !scene_params.persistent_data)
164         {
165                 /* if scene or session parameters changed, it's easier to simply re-create
166                  * them rather than trying to distinguish which settings need to be updated
167                  */
168
169                 delete session;
170
171                 create_session();
172
173                 return;
174         }
175
176         session->progress.reset();
177         scene->reset();
178
179         session->tile_manager.set_tile_order(session_params.tile_order);
180
181         /* peak memory usage should show current render peak, not peak for all renders
182          * made by this render session
183          */
184         session->stats.mem_peak = session->stats.mem_used;
185
186         /* sync object should be re-created */
187         sync = new BlenderSync(b_engine, b_data, b_scene, scene, !background, session->progress, is_cpu);
188
189         /* for final render we will do full data sync per render layer, only
190          * do some basic syncing here, no objects or materials for speed */
191         sync->sync_render_layers(b_v3d, NULL);
192         sync->sync_integrator();
193         sync->sync_camera(b_render, b_engine.camera_override(), width, height);
194
195         BufferParams buffer_params = BlenderSync::get_buffer_params(b_render, PointerRNA_NULL, PointerRNA_NULL, scene->camera, width, height);
196         session->reset(buffer_params, session_params.samples);
197
198         b_engine.use_highlight_tiles(session_params.progressive_refine == false);
199
200         /* reset time */
201         start_resize_time = 0.0;
202 }
203
204 void BlenderSession::free_session()
205 {
206         if(sync)
207                 delete sync;
208
209         delete session;
210 }
211
212 static PassType get_pass_type(BL::RenderPass b_pass)
213 {
214         switch(b_pass.type()) {
215                 case BL::RenderPass::type_COMBINED:
216                         return PASS_COMBINED;
217
218                 case BL::RenderPass::type_Z:
219                         return PASS_DEPTH;
220                 case BL::RenderPass::type_MIST:
221                         return PASS_MIST;
222                 case BL::RenderPass::type_NORMAL:
223                         return PASS_NORMAL;
224                 case BL::RenderPass::type_OBJECT_INDEX:
225                         return PASS_OBJECT_ID;
226                 case BL::RenderPass::type_UV:
227                         return PASS_UV;
228                 case BL::RenderPass::type_VECTOR:
229                         return PASS_MOTION;
230                 case BL::RenderPass::type_MATERIAL_INDEX:
231                         return PASS_MATERIAL_ID;
232
233                 case BL::RenderPass::type_DIFFUSE_DIRECT:
234                         return PASS_DIFFUSE_DIRECT;
235                 case BL::RenderPass::type_GLOSSY_DIRECT:
236                         return PASS_GLOSSY_DIRECT;
237                 case BL::RenderPass::type_TRANSMISSION_DIRECT:
238                         return PASS_TRANSMISSION_DIRECT;
239                 case BL::RenderPass::type_SUBSURFACE_DIRECT:
240                         return PASS_SUBSURFACE_DIRECT;
241
242                 case BL::RenderPass::type_DIFFUSE_INDIRECT:
243                         return PASS_DIFFUSE_INDIRECT;
244                 case BL::RenderPass::type_GLOSSY_INDIRECT:
245                         return PASS_GLOSSY_INDIRECT;
246                 case BL::RenderPass::type_TRANSMISSION_INDIRECT:
247                         return PASS_TRANSMISSION_INDIRECT;
248                 case BL::RenderPass::type_SUBSURFACE_INDIRECT:
249                         return PASS_SUBSURFACE_INDIRECT;
250
251                 case BL::RenderPass::type_DIFFUSE_COLOR:
252                         return PASS_DIFFUSE_COLOR;
253                 case BL::RenderPass::type_GLOSSY_COLOR:
254                         return PASS_GLOSSY_COLOR;
255                 case BL::RenderPass::type_TRANSMISSION_COLOR:
256                         return PASS_TRANSMISSION_COLOR;
257                 case BL::RenderPass::type_SUBSURFACE_COLOR:
258                         return PASS_SUBSURFACE_COLOR;
259
260                 case BL::RenderPass::type_EMIT:
261                         return PASS_EMISSION;
262                 case BL::RenderPass::type_ENVIRONMENT:
263                         return PASS_BACKGROUND;
264                 case BL::RenderPass::type_AO:
265                         return PASS_AO;
266                 case BL::RenderPass::type_SHADOW:
267                         return PASS_SHADOW;
268
269                 case BL::RenderPass::type_DIFFUSE:
270                 case BL::RenderPass::type_COLOR:
271                 case BL::RenderPass::type_REFRACTION:
272                 case BL::RenderPass::type_SPECULAR:
273                 case BL::RenderPass::type_REFLECTION:
274                         return PASS_NONE;
275 #ifdef WITH_CYCLES_DEBUG
276                 case BL::RenderPass::type_DEBUG:
277                 {
278                         if(b_pass.debug_type() == BL::RenderPass::debug_type_BVH_TRAVERSAL_STEPS)
279                                 return PASS_BVH_TRAVERSAL_STEPS;
280                         if(b_pass.debug_type() == BL::RenderPass::debug_type_BVH_TRAVERSED_INSTANCES)
281                                 return PASS_BVH_TRAVERSED_INSTANCES;
282                         if(b_pass.debug_type() == BL::RenderPass::debug_type_RAY_BOUNCES)
283                                 return PASS_RAY_BOUNCES;
284                         break;
285                 }
286 #endif
287         }
288         
289         return PASS_NONE;
290 }
291
292 static ShaderEvalType get_shader_type(const string& pass_type)
293 {
294         const char *shader_type = pass_type.c_str();
295
296         /* data passes */
297         if(strcmp(shader_type, "NORMAL")==0)
298                 return SHADER_EVAL_NORMAL;
299         else if(strcmp(shader_type, "UV")==0)
300                 return SHADER_EVAL_UV;
301         else if(strcmp(shader_type, "DIFFUSE_COLOR")==0)
302                 return SHADER_EVAL_DIFFUSE_COLOR;
303         else if(strcmp(shader_type, "GLOSSY_COLOR")==0)
304                 return SHADER_EVAL_GLOSSY_COLOR;
305         else if(strcmp(shader_type, "TRANSMISSION_COLOR")==0)
306                 return SHADER_EVAL_TRANSMISSION_COLOR;
307         else if(strcmp(shader_type, "SUBSURFACE_COLOR")==0)
308                 return SHADER_EVAL_SUBSURFACE_COLOR;
309         else if(strcmp(shader_type, "EMIT")==0)
310                 return SHADER_EVAL_EMISSION;
311
312         /* light passes */
313         else if(strcmp(shader_type, "AO")==0)
314                 return SHADER_EVAL_AO;
315         else if(strcmp(shader_type, "COMBINED")==0)
316                 return SHADER_EVAL_COMBINED;
317         else if(strcmp(shader_type, "SHADOW")==0)
318                 return SHADER_EVAL_SHADOW;
319         else if(strcmp(shader_type, "DIFFUSE_DIRECT")==0)
320                 return SHADER_EVAL_DIFFUSE_DIRECT;
321         else if(strcmp(shader_type, "GLOSSY_DIRECT")==0)
322                 return SHADER_EVAL_GLOSSY_DIRECT;
323         else if(strcmp(shader_type, "TRANSMISSION_DIRECT")==0)
324                 return SHADER_EVAL_TRANSMISSION_DIRECT;
325         else if(strcmp(shader_type, "SUBSURFACE_DIRECT")==0)
326                 return SHADER_EVAL_SUBSURFACE_DIRECT;
327         else if(strcmp(shader_type, "DIFFUSE_INDIRECT")==0)
328                 return SHADER_EVAL_DIFFUSE_INDIRECT;
329         else if(strcmp(shader_type, "GLOSSY_INDIRECT")==0)
330                 return SHADER_EVAL_GLOSSY_INDIRECT;
331         else if(strcmp(shader_type, "TRANSMISSION_INDIRECT")==0)
332                 return SHADER_EVAL_TRANSMISSION_INDIRECT;
333         else if(strcmp(shader_type, "SUBSURFACE_INDIRECT")==0)
334                 return SHADER_EVAL_SUBSURFACE_INDIRECT;
335
336         /* extra */
337         else if(strcmp(shader_type, "ENVIRONMENT")==0)
338                 return SHADER_EVAL_ENVIRONMENT;
339
340         else
341                 return SHADER_EVAL_BAKE;
342 }
343
344 static BL::RenderResult begin_render_result(BL::RenderEngine b_engine, int x, int y, int w, int h, const char *layername, const char *viewname)
345 {
346         return b_engine.begin_result(x, y, w, h, layername, viewname);
347 }
348
349 static void end_render_result(BL::RenderEngine b_engine, BL::RenderResult b_rr, bool cancel, bool do_merge_results)
350 {
351         b_engine.end_result(b_rr, (int)cancel, (int)do_merge_results);
352 }
353
354 void BlenderSession::do_write_update_render_tile(RenderTile& rtile, bool do_update_only)
355 {
356         BufferParams& params = rtile.buffers->params;
357         int x = params.full_x - session->tile_manager.params.full_x;
358         int y = params.full_y - session->tile_manager.params.full_y;
359         int w = params.width;
360         int h = params.height;
361
362         /* get render result */
363         BL::RenderResult b_rr = begin_render_result(b_engine, x, y, w, h, b_rlay_name.c_str(), b_rview_name.c_str());
364
365         /* can happen if the intersected rectangle gives 0 width or height */
366         if(b_rr.ptr.data == NULL) {
367                 return;
368         }
369
370         BL::RenderResult::layers_iterator b_single_rlay;
371         b_rr.layers.begin(b_single_rlay);
372
373         /* layer will be missing if it was disabled in the UI */
374         if(b_single_rlay == b_rr.layers.end())
375                 return;
376
377         BL::RenderLayer b_rlay = *b_single_rlay;
378
379         if(do_update_only) {
380                 /* update only needed */
381
382                 if(rtile.sample != 0) {
383                         /* sample would be zero at initial tile update, which is only needed
384                          * to tag tile form blender side as IN PROGRESS for proper highlight
385                          * no buffers should be sent to blender yet
386                          */
387                         update_render_result(b_rr, b_rlay, rtile);
388                 }
389
390                 end_render_result(b_engine, b_rr, true, true);
391         }
392         else {
393                 /* write result */
394                 write_render_result(b_rr, b_rlay, rtile);
395                 end_render_result(b_engine, b_rr, false, true);
396         }
397 }
398
399 void BlenderSession::write_render_tile(RenderTile& rtile)
400 {
401         do_write_update_render_tile(rtile, false);
402 }
403
404 void BlenderSession::update_render_tile(RenderTile& rtile)
405 {
406         /* use final write for preview renders, otherwise render result wouldn't be
407          * be updated in blender side
408          * would need to be investigated a bit further, but for now shall be fine
409          */
410         if(!b_engine.is_preview())
411                 do_write_update_render_tile(rtile, true);
412         else
413                 do_write_update_render_tile(rtile, false);
414 }
415
416 void BlenderSession::render()
417 {
418         /* set callback to write out render results */
419         session->write_render_tile_cb = function_bind(&BlenderSession::write_render_tile, this, _1);
420         session->update_render_tile_cb = function_bind(&BlenderSession::update_render_tile, this, _1);
421
422         /* get buffer parameters */
423         SessionParams session_params = BlenderSync::get_session_params(b_engine, b_userpref, b_scene, background);
424         BufferParams buffer_params = BlenderSync::get_buffer_params(b_render, b_v3d, b_rv3d, scene->camera, width, height);
425
426         /* render each layer */
427         BL::RenderSettings r = b_scene.render();
428         BL::RenderSettings::layers_iterator b_layer_iter;
429         BL::RenderResult::views_iterator b_view_iter;
430         
431         for(r.layers.begin(b_layer_iter); b_layer_iter != r.layers.end(); ++b_layer_iter) {
432                 b_rlay_name = b_layer_iter->name();
433
434                 /* temporary render result to find needed passes and views */
435                 BL::RenderResult b_rr = begin_render_result(b_engine, 0, 0, 1, 1, b_rlay_name.c_str(), NULL);
436                 BL::RenderResult::layers_iterator b_single_rlay;
437                 b_rr.layers.begin(b_single_rlay);
438
439                 /* layer will be missing if it was disabled in the UI */
440                 if(b_single_rlay == b_rr.layers.end()) {
441                         end_render_result(b_engine, b_rr, true, false);
442                         continue;
443                 }
444
445                 BL::RenderLayer b_rlay = *b_single_rlay;
446
447                 /* add passes */
448                 vector<Pass> passes;
449                 Pass::add(PASS_COMBINED, passes);
450 #ifdef WITH_CYCLES_DEBUG
451                 Pass::add(PASS_BVH_TRAVERSAL_STEPS, passes);
452                 /* Pass::add(PASS_RAY_BOUNCES, passes); */
453 #endif
454
455                 if(session_params.device.advanced_shading) {
456
457                         /* loop over passes */
458                         BL::RenderLayer::passes_iterator b_pass_iter;
459
460                         for(b_rlay.passes.begin(b_pass_iter); b_pass_iter != b_rlay.passes.end(); ++b_pass_iter) {
461                                 BL::RenderPass b_pass(*b_pass_iter);
462                                 PassType pass_type = get_pass_type(b_pass);
463
464                                 if(pass_type == PASS_MOTION && scene->integrator->motion_blur)
465                                         continue;
466                                 if(pass_type != PASS_NONE)
467                                         Pass::add(pass_type, passes);
468                         }
469                 }
470
471                 buffer_params.passes = passes;
472                 scene->film->pass_alpha_threshold = b_layer_iter->pass_alpha_threshold();
473                 scene->film->tag_passes_update(scene, passes);
474                 scene->film->tag_update(scene);
475                 scene->integrator->tag_update(scene);
476
477                 for(b_rr.views.begin(b_view_iter); b_view_iter != b_rr.views.end(); ++b_view_iter) {
478                         b_rview_name = b_view_iter->name();
479
480                         /* set the current view */
481                         b_engine.active_view_set(b_rview_name.c_str());
482
483                         /* update scene */
484                         sync->sync_camera(b_render, b_engine.camera_override(), width, height);
485                         sync->sync_data(b_render,
486                                         b_v3d,
487                                         b_engine.camera_override(),
488                                         width, height,
489                                         &python_thread_state,
490                                         b_rlay_name.c_str());
491
492                         /* update number of samples per layer */
493                         int samples = sync->get_layer_samples();
494                         bool bound_samples = sync->get_layer_bound_samples();
495
496                         if(samples != 0 && (!bound_samples || (samples < session_params.samples)))
497                                 session->reset(buffer_params, samples);
498                         else
499                                 session->reset(buffer_params, session_params.samples);
500
501                         /* render */
502                         session->start();
503                         session->wait();
504
505                         if(session->progress.get_cancel())
506                                 break;
507                 }
508
509                 /* free result without merging */
510                 end_render_result(b_engine, b_rr, true, false);
511
512                 if(session->progress.get_cancel())
513                         break;
514         }
515
516         double total_time, render_time;
517         session->progress.get_time(total_time, render_time);
518         VLOG(1) << "Total render time: " << total_time;
519         VLOG(1) << "Render time (without synchronization): " << render_time;
520
521         /* clear callback */
522         session->write_render_tile_cb = function_null;
523         session->update_render_tile_cb = function_null;
524
525         /* free all memory used (host and device), so we wouldn't leave render
526          * engine with extra memory allocated
527          */
528
529         session->device_free();
530
531         delete sync;
532         sync = NULL;
533 }
534
535 static void populate_bake_data(BakeData *data, const int object_id, BL::BakePixel pixel_array, const int num_pixels)
536 {
537         BL::BakePixel bp = pixel_array;
538
539         int i;
540         for(i=0; i < num_pixels; i++) {
541                 if(bp.object_id() == object_id) {
542                         data->set(i, bp.primitive_id(), bp.uv(), bp.du_dx(), bp.du_dy(), bp.dv_dx(), bp.dv_dy());
543                 } else {
544                         data->set_null(i);
545                 }
546                 bp = bp.next();
547         }
548 }
549
550 void BlenderSession::bake(BL::Object b_object, const string& pass_type, const int object_id, BL::BakePixel pixel_array, const size_t num_pixels, const int /*depth*/, float result[])
551 {
552         ShaderEvalType shader_type = get_shader_type(pass_type);
553         size_t object_index = OBJECT_NONE;
554         int tri_offset = 0;
555
556         /* Set baking flag in advance, so kernel loading can check if we need
557          * any baking capabilities.
558          */
559         scene->bake_manager->set_baking(true);
560
561         /* ensure kernels are loaded before we do any scene updates */
562         session->load_kernels();
563
564         if(session->progress.get_cancel())
565                 return;
566
567         if(shader_type == SHADER_EVAL_UV) {
568                 /* force UV to be available */
569                 Pass::add(PASS_UV, scene->film->passes);
570         }
571
572         if(BakeManager::is_light_pass(shader_type)) {
573                 /* force use_light_pass to be true */
574                 Pass::add(PASS_LIGHT, scene->film->passes);
575         }
576
577         /* create device and update scene */
578         scene->film->tag_update(scene);
579         scene->integrator->tag_update(scene);
580
581         /* update scene */
582         sync->sync_camera(b_render, b_engine.camera_override(), width, height);
583         sync->sync_data(b_render,
584                         b_v3d,
585                         b_engine.camera_override(),
586                         width, height,
587                         &python_thread_state,
588                         b_rlay_name.c_str());
589
590         /* get buffer parameters */
591         SessionParams session_params = BlenderSync::get_session_params(b_engine, b_userpref, b_scene, background);
592         BufferParams buffer_params = BlenderSync::get_buffer_params(b_render, b_v3d, b_rv3d, scene->camera, width, height);
593
594         scene->bake_manager->set_shader_limit((size_t)b_engine.tile_x(), (size_t)b_engine.tile_y());
595
596         /* set number of samples */
597         session->tile_manager.set_samples(session_params.samples);
598         session->reset(buffer_params, session_params.samples);
599         session->update_scene();
600
601         /* find object index. todo: is arbitrary - copied from mesh_displace.cpp */
602         for(size_t i = 0; i < scene->objects.size(); i++) {
603                 if(strcmp(scene->objects[i]->name.c_str(), b_object.name().c_str()) == 0) {
604                         object_index = i;
605                         tri_offset = scene->objects[i]->mesh->tri_offset;
606                         break;
607                 }
608         }
609
610         /* when used, non-instanced convention: object = ~object */
611         int object = ~object_index;
612
613         BakeData *bake_data = scene->bake_manager->init(object, tri_offset, num_pixels);
614
615         populate_bake_data(bake_data, object_id, pixel_array, num_pixels);
616
617         /* set number of samples */
618         session->tile_manager.set_samples(session_params.samples);
619         session->reset(buffer_params, session_params.samples);
620         session->update_scene();
621
622         session->progress.set_update_callback(function_bind(&BlenderSession::update_bake_progress, this));
623
624         scene->bake_manager->bake(scene->device, &scene->dscene, scene, session->progress, shader_type, bake_data, result);
625
626         /* free all memory used (host and device), so we wouldn't leave render
627          * engine with extra memory allocated
628          */
629
630         session->device_free();
631
632         delete sync;
633         sync = NULL;
634 }
635
636 void BlenderSession::do_write_update_render_result(BL::RenderResult b_rr, BL::RenderLayer b_rlay, RenderTile& rtile, bool do_update_only)
637 {
638         RenderBuffers *buffers = rtile.buffers;
639
640         /* copy data from device */
641         if(!buffers->copy_from_device())
642                 return;
643
644         BufferParams& params = buffers->params;
645         float exposure = scene->film->exposure;
646
647         vector<float> pixels(params.width*params.height*4);
648
649         if(!do_update_only) {
650                 /* copy each pass */
651                 BL::RenderLayer::passes_iterator b_iter;
652
653                 for(b_rlay.passes.begin(b_iter); b_iter != b_rlay.passes.end(); ++b_iter) {
654                         BL::RenderPass b_pass(*b_iter);
655
656                         /* find matching pass type */
657                         PassType pass_type = get_pass_type(b_pass);
658                         int components = b_pass.channels();
659
660                         /* copy pixels */
661                         if(!buffers->get_pass_rect(pass_type, exposure, rtile.sample, components, &pixels[0]))
662                                 memset(&pixels[0], 0, pixels.size()*sizeof(float));
663
664                         b_pass.rect(&pixels[0]);
665                 }
666         }
667         else {
668                 /* copy combined pass */
669                 BL::RenderPass b_combined_pass(b_rlay.passes.find_by_type(BL::RenderPass::type_COMBINED, b_rview_name.c_str()));
670                 if(buffers->get_pass_rect(PASS_COMBINED, exposure, rtile.sample, 4, &pixels[0]))
671                         b_combined_pass.rect(&pixels[0]);
672         }
673
674         /* tag result as updated */
675         b_engine.update_result(b_rr);
676 }
677
678 void BlenderSession::write_render_result(BL::RenderResult b_rr, BL::RenderLayer b_rlay, RenderTile& rtile)
679 {
680         do_write_update_render_result(b_rr, b_rlay, rtile, false);
681 }
682
683 void BlenderSession::update_render_result(BL::RenderResult b_rr, BL::RenderLayer b_rlay, RenderTile& rtile)
684 {
685         do_write_update_render_result(b_rr, b_rlay, rtile, true);
686 }
687
688 void BlenderSession::synchronize()
689 {
690         /* only used for viewport render */
691         if(!b_v3d)
692                 return;
693
694         /* on session/scene parameter changes, we recreate session entirely */
695         SessionParams session_params = BlenderSync::get_session_params(b_engine, b_userpref, b_scene, background);
696         const bool is_cpu = session_params.device.type == DEVICE_CPU;
697         SceneParams scene_params = BlenderSync::get_scene_params(b_scene, background, is_cpu);
698         bool session_pause = BlenderSync::get_session_pause(b_scene, background);
699
700         if(session->params.modified(session_params) ||
701            scene->params.modified(scene_params))
702         {
703                 free_session();
704                 create_session();
705                 session->start();
706                 return;
707         }
708
709         /* increase samples, but never decrease */
710         session->set_samples(session_params.samples);
711         session->set_pause(session_pause);
712
713         /* copy recalc flags, outside of mutex so we can decide to do the real
714          * synchronization at a later time to not block on running updates */
715         sync->sync_recalc();
716
717         /* don't do synchronization if on pause */
718         if(session_pause) {
719                 tag_update();
720                 return;
721         }
722
723         /* try to acquire mutex. if we don't want to or can't, come back later */
724         if(!session->ready_to_reset() || !session->scene->mutex.try_lock()) {
725                 tag_update();
726                 return;
727         }
728
729         /* data and camera synchronize */
730         sync->sync_data(b_render,
731                         b_v3d,
732                         b_engine.camera_override(),
733                         width, height,
734                         &python_thread_state,
735                         b_rlay_name.c_str());
736
737         if(b_rv3d)
738                 sync->sync_view(b_v3d, b_rv3d, width, height);
739         else
740                 sync->sync_camera(b_render, b_engine.camera_override(), width, height);
741
742         /* unlock */
743         session->scene->mutex.unlock();
744
745         /* reset if needed */
746         if(scene->need_reset()) {
747                 BufferParams buffer_params = BlenderSync::get_buffer_params(b_render, b_v3d, b_rv3d, scene->camera, width, height);
748                 session->reset(buffer_params, session_params.samples);
749
750                 /* reset time */
751                 start_resize_time = 0.0;
752         }
753 }
754
755 bool BlenderSession::draw(int w, int h)
756 {
757         /* pause in redraw in case update is not being called due to final render */
758         session->set_pause(BlenderSync::get_session_pause(b_scene, background));
759
760         /* before drawing, we verify camera and viewport size changes, because
761          * we do not get update callbacks for those, we must detect them here */
762         if(session->ready_to_reset()) {
763                 bool reset = false;
764
765                 /* if dimensions changed, reset */
766                 if(width != w || height != h) {
767                         if(start_resize_time == 0.0) {
768                                 /* don't react immediately to resizes to avoid flickery resizing
769                                  * of the viewport, and some window managers changing the window
770                                  * size temporarily on unminimize */
771                                 start_resize_time = time_dt();
772                                 tag_redraw();
773                         }
774                         else if(time_dt() - start_resize_time < 0.2) {
775                                 tag_redraw();
776                         }
777                         else {
778                                 width = w;
779                                 height = h;
780                                 reset = true;
781                         }
782                 }
783
784                 /* try to acquire mutex. if we can't, come back later */
785                 if(!session->scene->mutex.try_lock()) {
786                         tag_update();
787                 }
788                 else {
789                         /* update camera from 3d view */
790
791                         sync->sync_view(b_v3d, b_rv3d, width, height);
792
793                         if(scene->camera->need_update)
794                                 reset = true;
795
796                         session->scene->mutex.unlock();
797                 }
798
799                 /* reset if requested */
800                 if(reset) {
801                         SessionParams session_params = BlenderSync::get_session_params(b_engine, b_userpref, b_scene, background);
802                         BufferParams buffer_params = BlenderSync::get_buffer_params(b_render, b_v3d, b_rv3d, scene->camera, width, height);
803                         bool session_pause = BlenderSync::get_session_pause(b_scene, background);
804
805                         if(session_pause == false) {
806                                 session->reset(buffer_params, session_params.samples);
807                                 start_resize_time = 0.0;
808                         }
809                 }
810         }
811         else {
812                 tag_update();
813         }
814
815         /* update status and progress for 3d view draw */
816         update_status_progress();
817
818         /* draw */
819         BufferParams buffer_params = BlenderSync::get_buffer_params(b_render, b_v3d, b_rv3d, scene->camera, width, height);
820         DeviceDrawParams draw_params;
821
822         if(session->params.display_buffer_linear) {
823                 draw_params.bind_display_space_shader_cb = function_bind(&BL::RenderEngine::bind_display_space_shader, &b_engine, b_scene);
824                 draw_params.unbind_display_space_shader_cb = function_bind(&BL::RenderEngine::unbind_display_space_shader, &b_engine);
825         }
826
827         return !session->draw(buffer_params, draw_params);
828 }
829
830 void BlenderSession::get_status(string& status, string& substatus)
831 {
832         session->progress.get_status(status, substatus);
833 }
834
835 void BlenderSession::get_progress(float& progress, double& total_time, double& render_time)
836 {
837         double tile_time;
838         int tile, sample, samples_per_tile;
839         int tile_total = session->tile_manager.state.num_tiles;
840         int samples = session->tile_manager.state.sample + 1;
841         int total_samples = session->tile_manager.num_samples;
842
843         session->progress.get_tile(tile, total_time, render_time, tile_time);
844
845         sample = session->progress.get_sample();
846         samples_per_tile = session->tile_manager.num_samples;
847
848         if(background && samples_per_tile && tile_total)
849                 progress = ((float)sample / (float)(tile_total * samples_per_tile));
850         else if(!background && samples > 0 && total_samples != USHRT_MAX)
851                 progress = ((float)samples) / total_samples;
852         else
853                 progress = 0.0;
854 }
855
856 void BlenderSession::update_bake_progress()
857 {
858         float progress;
859         int sample, samples_per_task, parts_total;
860
861         sample = session->progress.get_sample();
862         samples_per_task = scene->bake_manager->num_samples;
863         parts_total = scene->bake_manager->num_parts;
864
865         if(samples_per_task)
866                 progress = ((float)sample / (float)(parts_total * samples_per_task));
867         else
868                 progress = 0.0;
869
870         if(progress != last_progress) {
871                 b_engine.update_progress(progress);
872                 last_progress = progress;
873         }
874 }
875
876 void BlenderSession::update_status_progress()
877 {
878         string timestatus, status, substatus;
879         string scene = "";
880         float progress;
881         double total_time, remaining_time = 0, render_time;
882         char time_str[128];
883         float mem_used = (float)session->stats.mem_used / 1024.0f / 1024.0f;
884         float mem_peak = (float)session->stats.mem_peak / 1024.0f / 1024.0f;
885
886         get_status(status, substatus);
887         get_progress(progress, total_time, render_time);
888
889         if(progress > 0)
890                 remaining_time = (1.0 - (double)progress) * (render_time / (double)progress);
891
892         if(background) {
893                 scene += " | " + b_scene.name();
894                 if(b_rlay_name != "")
895                         scene += ", "  + b_rlay_name;
896
897                 if(b_rview_name != "")
898                         scene += ", " + b_rview_name;
899         }
900         else {
901                 BLI_timecode_string_from_time_simple(time_str, sizeof(time_str), total_time);
902                 timestatus = "Time:" + string(time_str) + " | ";
903         }
904
905         if(remaining_time > 0) {
906                 BLI_timecode_string_from_time_simple(time_str, sizeof(time_str), remaining_time);
907                 timestatus += "Remaining:" + string(time_str) + " | ";
908         }
909
910         timestatus += string_printf("Mem:%.2fM, Peak:%.2fM", (double)mem_used, (double)mem_peak);
911
912         if(status.size() > 0)
913                 status = " | " + status;
914         if(substatus.size() > 0)
915                 status += " | " + substatus;
916
917         if(status != last_status) {
918                 b_engine.update_stats("", (timestatus + scene + status).c_str());
919                 b_engine.update_memory_stats(mem_used, mem_peak);
920                 last_status = status;
921         }
922         if(progress != last_progress) {
923                 b_engine.update_progress(progress);
924                 last_progress = progress;
925         }
926
927         if(session->progress.get_error()) {
928                 string error = session->progress.get_error_message();
929                 if(error != last_error) {
930                         /* TODO(sergey): Currently C++ RNA API doesn't let us to
931                          * use mnemonic name for the variable. Would be nice to
932                          * have this figured out.
933                          *
934                          * For until then, 1 << 5 means RPT_ERROR.
935                          */
936                         b_engine.report(1 << 5, error.c_str());
937                         b_engine.error_set(error.c_str());
938                         last_error = error;
939                 }
940         }
941 }
942
943 void BlenderSession::tag_update()
944 {
945         /* tell blender that we want to get another update callback */
946         b_engine.tag_update();
947 }
948
949 void BlenderSession::tag_redraw()
950 {
951         if(background) {
952                 /* update stats and progress, only for background here because
953                  * in 3d view we do it in draw for thread safety reasons */
954                 update_status_progress();
955
956                 /* offline render, redraw if timeout passed */
957                 if(time_dt() - last_redraw_time > 1.0) {
958                         b_engine.tag_redraw();
959                         last_redraw_time = time_dt();
960                 }
961         }
962         else {
963                 /* tell blender that we want to redraw */
964                 b_engine.tag_redraw();
965         }
966 }
967
968 void BlenderSession::test_cancel()
969 {
970         /* test if we need to cancel rendering */
971         if(background)
972                 if(b_engine.test_break())
973                         session->progress.set_cancel("Cancelled");
974 }
975
976 /* builtin image file name is actually an image datablock name with
977  * absolute sequence frame number concatenated via '@' character
978  *
979  * this function splits frame from builtin name
980  */
981 int BlenderSession::builtin_image_frame(const string &builtin_name)
982 {
983         int last = builtin_name.find_last_of('@');
984         return atoi(builtin_name.substr(last + 1, builtin_name.size() - last - 1).c_str());
985 }
986
987 void BlenderSession::builtin_image_info(const string &builtin_name, void *builtin_data, bool &is_float, int &width, int &height, int &depth, int &channels)
988 {
989         /* empty image */
990         is_float = false;
991         width = 0;
992         height = 0;
993         depth = 0;
994         channels = 0;
995
996         if(!builtin_data)
997                 return;
998
999         /* recover ID pointer */
1000         PointerRNA ptr;
1001         RNA_id_pointer_create((ID*)builtin_data, &ptr);
1002         BL::ID b_id(ptr);
1003
1004         if(b_id.is_a(&RNA_Image)) {
1005                 /* image data */
1006                 BL::Image b_image(b_id);
1007
1008                 is_float = b_image.is_float();
1009                 width = b_image.size()[0];
1010                 height = b_image.size()[1];
1011                 depth = 1;
1012                 channels = b_image.channels();
1013         }
1014         else if(b_id.is_a(&RNA_Object)) {
1015                 /* smoke volume data */
1016                 BL::Object b_ob(b_id);
1017                 BL::SmokeDomainSettings b_domain = object_smoke_domain_find(b_ob);
1018
1019                 if(!b_domain)
1020                         return;
1021
1022                 if(builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_DENSITY) ||
1023                    builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_FLAME))
1024                         channels = 1;
1025                 else if(builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_COLOR))
1026                         channels = 4;
1027                 else
1028                         return;
1029
1030                 int3 resolution = get_int3(b_domain.domain_resolution());
1031                 int amplify = (b_domain.use_high_resolution())? b_domain.amplify() + 1: 1;
1032
1033                 width = resolution.x * amplify;
1034                 height = resolution.y * amplify;
1035                 depth = resolution.z * amplify;
1036
1037                 is_float = true;
1038         }
1039         else {
1040                 /* TODO(sergey): Check we're indeed in shader node tree. */
1041                 PointerRNA ptr;
1042                 RNA_pointer_create(NULL, &RNA_Node, builtin_data, &ptr);
1043                 BL::Node b_node(ptr);
1044                 if(b_node.is_a(&RNA_ShaderNodeTexPointDensity)) {
1045                         BL::ShaderNodeTexPointDensity b_point_density_node(b_node);
1046                         channels = 4;
1047                         width = height = depth = b_point_density_node.resolution();
1048                         is_float = true;
1049                 }
1050         }
1051 }
1052
1053 bool BlenderSession::builtin_image_pixels(const string &builtin_name, void *builtin_data, unsigned char *pixels)
1054 {
1055         if(!builtin_data)
1056                 return false;
1057
1058         int frame = builtin_image_frame(builtin_name);
1059
1060         PointerRNA ptr;
1061         RNA_id_pointer_create((ID*)builtin_data, &ptr);
1062         BL::Image b_image(ptr);
1063
1064         int width = b_image.size()[0];
1065         int height = b_image.size()[1];
1066         int channels = b_image.channels();
1067
1068         unsigned char *image_pixels;
1069         image_pixels = image_get_pixels_for_frame(b_image, frame);
1070         size_t num_pixels = ((size_t)width) * height;
1071
1072         if(image_pixels) {
1073                 memcpy(pixels, image_pixels, num_pixels * channels * sizeof(unsigned char));
1074                 MEM_freeN(image_pixels);
1075         }
1076         else {
1077                 if(channels == 1) {
1078                         memset(pixels, 0, num_pixels * sizeof(unsigned char));
1079                 }
1080                 else {
1081                         unsigned char *cp = pixels;
1082                         for(size_t i = 0; i < num_pixels; i++, cp += channels) {
1083                                 cp[0] = 255;
1084                                 cp[1] = 0;
1085                                 cp[2] = 255;
1086                                 if(channels == 4)
1087                                         cp[3] = 255;
1088                         }
1089                 }
1090         }
1091
1092         /* premultiply, byte images are always straight for blender */
1093         unsigned char *cp = pixels;
1094         for(size_t i = 0; i < num_pixels; i++, cp += channels) {
1095                 cp[0] = (cp[0] * cp[3]) >> 8;
1096                 cp[1] = (cp[1] * cp[3]) >> 8;
1097                 cp[2] = (cp[2] * cp[3]) >> 8;
1098         }
1099
1100         return true;
1101 }
1102
1103 bool BlenderSession::builtin_image_float_pixels(const string &builtin_name, void *builtin_data, float *pixels)
1104 {
1105         if(!builtin_data)
1106                 return false;
1107
1108         PointerRNA ptr;
1109         RNA_id_pointer_create((ID*)builtin_data, &ptr);
1110         BL::ID b_id(ptr);
1111
1112         if(b_id.is_a(&RNA_Image)) {
1113                 /* image data */
1114                 BL::Image b_image(b_id);
1115                 int frame = builtin_image_frame(builtin_name);
1116
1117                 int width = b_image.size()[0];
1118                 int height = b_image.size()[1];
1119                 int channels = b_image.channels();
1120
1121                 float *image_pixels;
1122                 image_pixels = image_get_float_pixels_for_frame(b_image, frame);
1123                 size_t num_pixels = ((size_t)width) * height;
1124
1125                 if(image_pixels) {
1126                         memcpy(pixels, image_pixels, num_pixels * channels * sizeof(float));
1127                         MEM_freeN(image_pixels);
1128                 }
1129                 else {
1130                         if(channels == 1) {
1131                                 memset(pixels, 0, num_pixels * sizeof(float));
1132                         }
1133                         else {
1134                                 float *fp = pixels;
1135                                 for(int i = 0; i < num_pixels; i++, fp += channels) {
1136                                         fp[0] = 1.0f;
1137                                         fp[1] = 0.0f;
1138                                         fp[2] = 1.0f;
1139                                         if(channels == 4)
1140                                                 fp[3] = 1.0f;
1141                                 }
1142                         }
1143                 }
1144
1145                 return true;
1146         }
1147         else if(b_id.is_a(&RNA_Object)) {
1148                 /* smoke volume data */
1149                 BL::Object b_ob(b_id);
1150                 BL::SmokeDomainSettings b_domain = object_smoke_domain_find(b_ob);
1151
1152                 if(!b_domain)
1153                         return false;
1154
1155                 int3 resolution = get_int3(b_domain.domain_resolution());
1156                 int length, amplify = (b_domain.use_high_resolution())? b_domain.amplify() + 1: 1;
1157
1158                 int width = resolution.x * amplify;
1159                 int height = resolution.y * amplify;
1160                 int depth = resolution.z * amplify;
1161                 size_t num_pixels = ((size_t)width) * height * depth;
1162
1163                 if(builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_DENSITY)) {
1164                         SmokeDomainSettings_density_grid_get_length(&b_domain.ptr, &length);
1165
1166                         if(length == num_pixels) {
1167                                 SmokeDomainSettings_density_grid_get(&b_domain.ptr, pixels);
1168                                 return true;
1169                         }
1170                 }
1171                 else if(builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_FLAME)) {
1172                         /* this is in range 0..1, and interpreted by the OpenGL smoke viewer
1173                          * as 1500..3000 K with the first part faded to zero density */
1174                         SmokeDomainSettings_flame_grid_get_length(&b_domain.ptr, &length);
1175
1176                         if(length == num_pixels) {
1177                                 SmokeDomainSettings_flame_grid_get(&b_domain.ptr, pixels);
1178                                 return true;
1179                         }
1180                 }
1181                 else if(builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_COLOR)) {
1182                         /* the RGB is "premultiplied" by density for better interpolation results */
1183                         SmokeDomainSettings_color_grid_get_length(&b_domain.ptr, &length);
1184
1185                         if(length == num_pixels*4) {
1186                                 SmokeDomainSettings_color_grid_get(&b_domain.ptr, pixels);
1187                                 return true;
1188                         }
1189                 }
1190
1191                 fprintf(stderr, "Cycles error: unexpected smoke volume resolution, skipping\n");
1192         }
1193         else {
1194                 /* TODO(sergey): Check we're indeed in shader node tree. */
1195                 PointerRNA ptr;
1196                 RNA_pointer_create(NULL, &RNA_Node, builtin_data, &ptr);
1197                 BL::Node b_node(ptr);
1198                 if(b_node.is_a(&RNA_ShaderNodeTexPointDensity)) {
1199                         BL::ShaderNodeTexPointDensity b_point_density_node(b_node);
1200                         int length;
1201                         b_point_density_node.calc_point_density(b_scene, &length, &pixels);
1202                 }
1203         }
1204
1205         return false;
1206 }
1207
1208 CCL_NAMESPACE_END
1209