Cycles: Don't explicitly add debug passes, this is now handled via RNA
[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
451                 if(session_params.device.advanced_shading) {
452
453                         /* loop over passes */
454                         BL::RenderLayer::passes_iterator b_pass_iter;
455
456                         for(b_rlay.passes.begin(b_pass_iter); b_pass_iter != b_rlay.passes.end(); ++b_pass_iter) {
457                                 BL::RenderPass b_pass(*b_pass_iter);
458                                 PassType pass_type = get_pass_type(b_pass);
459
460                                 if(pass_type == PASS_MOTION && scene->integrator->motion_blur)
461                                         continue;
462                                 if(pass_type != PASS_NONE)
463                                         Pass::add(pass_type, passes);
464                         }
465                 }
466
467                 buffer_params.passes = passes;
468                 scene->film->pass_alpha_threshold = b_layer_iter->pass_alpha_threshold();
469                 scene->film->tag_passes_update(scene, passes);
470                 scene->film->tag_update(scene);
471                 scene->integrator->tag_update(scene);
472
473                 for(b_rr.views.begin(b_view_iter); b_view_iter != b_rr.views.end(); ++b_view_iter) {
474                         b_rview_name = b_view_iter->name();
475
476                         /* set the current view */
477                         b_engine.active_view_set(b_rview_name.c_str());
478
479                         /* update scene */
480                         sync->sync_camera(b_render, b_engine.camera_override(), width, height);
481                         sync->sync_data(b_render,
482                                         b_v3d,
483                                         b_engine.camera_override(),
484                                         width, height,
485                                         &python_thread_state,
486                                         b_rlay_name.c_str());
487
488                         /* update number of samples per layer */
489                         int samples = sync->get_layer_samples();
490                         bool bound_samples = sync->get_layer_bound_samples();
491
492                         if(samples != 0 && (!bound_samples || (samples < session_params.samples)))
493                                 session->reset(buffer_params, samples);
494                         else
495                                 session->reset(buffer_params, session_params.samples);
496
497                         /* render */
498                         session->start();
499                         session->wait();
500
501                         if(session->progress.get_cancel())
502                                 break;
503                 }
504
505                 /* free result without merging */
506                 end_render_result(b_engine, b_rr, true, false);
507
508                 if(session->progress.get_cancel())
509                         break;
510         }
511
512         double total_time, render_time;
513         session->progress.get_time(total_time, render_time);
514         VLOG(1) << "Total render time: " << total_time;
515         VLOG(1) << "Render time (without synchronization): " << render_time;
516
517         /* clear callback */
518         session->write_render_tile_cb = function_null;
519         session->update_render_tile_cb = function_null;
520
521         /* free all memory used (host and device), so we wouldn't leave render
522          * engine with extra memory allocated
523          */
524
525         session->device_free();
526
527         delete sync;
528         sync = NULL;
529 }
530
531 static void populate_bake_data(BakeData *data, const int object_id, BL::BakePixel pixel_array, const int num_pixels)
532 {
533         BL::BakePixel bp = pixel_array;
534
535         int i;
536         for(i=0; i < num_pixels; i++) {
537                 if(bp.object_id() == object_id) {
538                         data->set(i, bp.primitive_id(), bp.uv(), bp.du_dx(), bp.du_dy(), bp.dv_dx(), bp.dv_dy());
539                 } else {
540                         data->set_null(i);
541                 }
542                 bp = bp.next();
543         }
544 }
545
546 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[])
547 {
548         ShaderEvalType shader_type = get_shader_type(pass_type);
549         size_t object_index = OBJECT_NONE;
550         int tri_offset = 0;
551
552         /* Set baking flag in advance, so kernel loading can check if we need
553          * any baking capabilities.
554          */
555         scene->bake_manager->set_baking(true);
556
557         /* ensure kernels are loaded before we do any scene updates */
558         session->load_kernels();
559
560         if(session->progress.get_cancel())
561                 return;
562
563         if(shader_type == SHADER_EVAL_UV) {
564                 /* force UV to be available */
565                 Pass::add(PASS_UV, scene->film->passes);
566         }
567
568         if(BakeManager::is_light_pass(shader_type)) {
569                 /* force use_light_pass to be true */
570                 Pass::add(PASS_LIGHT, scene->film->passes);
571         }
572
573         /* create device and update scene */
574         scene->film->tag_update(scene);
575         scene->integrator->tag_update(scene);
576
577         /* update scene */
578         sync->sync_camera(b_render, b_engine.camera_override(), width, height);
579         sync->sync_data(b_render,
580                         b_v3d,
581                         b_engine.camera_override(),
582                         width, height,
583                         &python_thread_state,
584                         b_rlay_name.c_str());
585
586         /* get buffer parameters */
587         SessionParams session_params = BlenderSync::get_session_params(b_engine, b_userpref, b_scene, background);
588         BufferParams buffer_params = BlenderSync::get_buffer_params(b_render, b_v3d, b_rv3d, scene->camera, width, height);
589
590         scene->bake_manager->set_shader_limit((size_t)b_engine.tile_x(), (size_t)b_engine.tile_y());
591
592         /* set number of samples */
593         session->tile_manager.set_samples(session_params.samples);
594         session->reset(buffer_params, session_params.samples);
595         session->update_scene();
596
597         /* find object index. todo: is arbitrary - copied from mesh_displace.cpp */
598         for(size_t i = 0; i < scene->objects.size(); i++) {
599                 if(strcmp(scene->objects[i]->name.c_str(), b_object.name().c_str()) == 0) {
600                         object_index = i;
601                         tri_offset = scene->objects[i]->mesh->tri_offset;
602                         break;
603                 }
604         }
605
606         /* when used, non-instanced convention: object = ~object */
607         int object = ~object_index;
608
609         BakeData *bake_data = scene->bake_manager->init(object, tri_offset, num_pixels);
610
611         populate_bake_data(bake_data, object_id, pixel_array, num_pixels);
612
613         /* set number of samples */
614         session->tile_manager.set_samples(session_params.samples);
615         session->reset(buffer_params, session_params.samples);
616         session->update_scene();
617
618         session->progress.set_update_callback(function_bind(&BlenderSession::update_bake_progress, this));
619
620         scene->bake_manager->bake(scene->device, &scene->dscene, scene, session->progress, shader_type, bake_data, result);
621
622         /* free all memory used (host and device), so we wouldn't leave render
623          * engine with extra memory allocated
624          */
625
626         session->device_free();
627
628         delete sync;
629         sync = NULL;
630 }
631
632 void BlenderSession::do_write_update_render_result(BL::RenderResult b_rr, BL::RenderLayer b_rlay, RenderTile& rtile, bool do_update_only)
633 {
634         RenderBuffers *buffers = rtile.buffers;
635
636         /* copy data from device */
637         if(!buffers->copy_from_device())
638                 return;
639
640         BufferParams& params = buffers->params;
641         float exposure = scene->film->exposure;
642
643         vector<float> pixels(params.width*params.height*4);
644
645         if(!do_update_only) {
646                 /* copy each pass */
647                 BL::RenderLayer::passes_iterator b_iter;
648
649                 for(b_rlay.passes.begin(b_iter); b_iter != b_rlay.passes.end(); ++b_iter) {
650                         BL::RenderPass b_pass(*b_iter);
651
652                         /* find matching pass type */
653                         PassType pass_type = get_pass_type(b_pass);
654                         int components = b_pass.channels();
655
656                         /* copy pixels */
657                         if(!buffers->get_pass_rect(pass_type, exposure, rtile.sample, components, &pixels[0]))
658                                 memset(&pixels[0], 0, pixels.size()*sizeof(float));
659
660                         b_pass.rect(&pixels[0]);
661                 }
662         }
663         else {
664                 /* copy combined pass */
665                 BL::RenderPass b_combined_pass(b_rlay.passes.find_by_type(BL::RenderPass::type_COMBINED, b_rview_name.c_str()));
666                 if(buffers->get_pass_rect(PASS_COMBINED, exposure, rtile.sample, 4, &pixels[0]))
667                         b_combined_pass.rect(&pixels[0]);
668         }
669
670         /* tag result as updated */
671         b_engine.update_result(b_rr);
672 }
673
674 void BlenderSession::write_render_result(BL::RenderResult b_rr, BL::RenderLayer b_rlay, RenderTile& rtile)
675 {
676         do_write_update_render_result(b_rr, b_rlay, rtile, false);
677 }
678
679 void BlenderSession::update_render_result(BL::RenderResult b_rr, BL::RenderLayer b_rlay, RenderTile& rtile)
680 {
681         do_write_update_render_result(b_rr, b_rlay, rtile, true);
682 }
683
684 void BlenderSession::synchronize()
685 {
686         /* only used for viewport render */
687         if(!b_v3d)
688                 return;
689
690         /* on session/scene parameter changes, we recreate session entirely */
691         SessionParams session_params = BlenderSync::get_session_params(b_engine, b_userpref, b_scene, background);
692         const bool is_cpu = session_params.device.type == DEVICE_CPU;
693         SceneParams scene_params = BlenderSync::get_scene_params(b_scene, background, is_cpu);
694         bool session_pause = BlenderSync::get_session_pause(b_scene, background);
695
696         if(session->params.modified(session_params) ||
697            scene->params.modified(scene_params))
698         {
699                 free_session();
700                 create_session();
701                 session->start();
702                 return;
703         }
704
705         /* increase samples, but never decrease */
706         session->set_samples(session_params.samples);
707         session->set_pause(session_pause);
708
709         /* copy recalc flags, outside of mutex so we can decide to do the real
710          * synchronization at a later time to not block on running updates */
711         sync->sync_recalc();
712
713         /* don't do synchronization if on pause */
714         if(session_pause) {
715                 tag_update();
716                 return;
717         }
718
719         /* try to acquire mutex. if we don't want to or can't, come back later */
720         if(!session->ready_to_reset() || !session->scene->mutex.try_lock()) {
721                 tag_update();
722                 return;
723         }
724
725         /* data and camera synchronize */
726         sync->sync_data(b_render,
727                         b_v3d,
728                         b_engine.camera_override(),
729                         width, height,
730                         &python_thread_state,
731                         b_rlay_name.c_str());
732
733         if(b_rv3d)
734                 sync->sync_view(b_v3d, b_rv3d, width, height);
735         else
736                 sync->sync_camera(b_render, b_engine.camera_override(), width, height);
737
738         /* unlock */
739         session->scene->mutex.unlock();
740
741         /* reset if needed */
742         if(scene->need_reset()) {
743                 BufferParams buffer_params = BlenderSync::get_buffer_params(b_render, b_v3d, b_rv3d, scene->camera, width, height);
744                 session->reset(buffer_params, session_params.samples);
745
746                 /* reset time */
747                 start_resize_time = 0.0;
748         }
749 }
750
751 bool BlenderSession::draw(int w, int h)
752 {
753         /* pause in redraw in case update is not being called due to final render */
754         session->set_pause(BlenderSync::get_session_pause(b_scene, background));
755
756         /* before drawing, we verify camera and viewport size changes, because
757          * we do not get update callbacks for those, we must detect them here */
758         if(session->ready_to_reset()) {
759                 bool reset = false;
760
761                 /* if dimensions changed, reset */
762                 if(width != w || height != h) {
763                         if(start_resize_time == 0.0) {
764                                 /* don't react immediately to resizes to avoid flickery resizing
765                                  * of the viewport, and some window managers changing the window
766                                  * size temporarily on unminimize */
767                                 start_resize_time = time_dt();
768                                 tag_redraw();
769                         }
770                         else if(time_dt() - start_resize_time < 0.2) {
771                                 tag_redraw();
772                         }
773                         else {
774                                 width = w;
775                                 height = h;
776                                 reset = true;
777                         }
778                 }
779
780                 /* try to acquire mutex. if we can't, come back later */
781                 if(!session->scene->mutex.try_lock()) {
782                         tag_update();
783                 }
784                 else {
785                         /* update camera from 3d view */
786
787                         sync->sync_view(b_v3d, b_rv3d, width, height);
788
789                         if(scene->camera->need_update)
790                                 reset = true;
791
792                         session->scene->mutex.unlock();
793                 }
794
795                 /* reset if requested */
796                 if(reset) {
797                         SessionParams session_params = BlenderSync::get_session_params(b_engine, b_userpref, b_scene, background);
798                         BufferParams buffer_params = BlenderSync::get_buffer_params(b_render, b_v3d, b_rv3d, scene->camera, width, height);
799                         bool session_pause = BlenderSync::get_session_pause(b_scene, background);
800
801                         if(session_pause == false) {
802                                 session->reset(buffer_params, session_params.samples);
803                                 start_resize_time = 0.0;
804                         }
805                 }
806         }
807         else {
808                 tag_update();
809         }
810
811         /* update status and progress for 3d view draw */
812         update_status_progress();
813
814         /* draw */
815         BufferParams buffer_params = BlenderSync::get_buffer_params(b_render, b_v3d, b_rv3d, scene->camera, width, height);
816         DeviceDrawParams draw_params;
817
818         if(session->params.display_buffer_linear) {
819                 draw_params.bind_display_space_shader_cb = function_bind(&BL::RenderEngine::bind_display_space_shader, &b_engine, b_scene);
820                 draw_params.unbind_display_space_shader_cb = function_bind(&BL::RenderEngine::unbind_display_space_shader, &b_engine);
821         }
822
823         return !session->draw(buffer_params, draw_params);
824 }
825
826 void BlenderSession::get_status(string& status, string& substatus)
827 {
828         session->progress.get_status(status, substatus);
829 }
830
831 void BlenderSession::get_progress(float& progress, double& total_time, double& render_time)
832 {
833         double tile_time;
834         int tile, sample, samples_per_tile;
835         int tile_total = session->tile_manager.state.num_tiles;
836         int samples = session->tile_manager.state.sample + 1;
837         int total_samples = session->tile_manager.num_samples;
838
839         session->progress.get_tile(tile, total_time, render_time, tile_time);
840
841         sample = session->progress.get_sample();
842         samples_per_tile = session->tile_manager.num_samples;
843
844         if(background && samples_per_tile && tile_total)
845                 progress = ((float)sample / (float)(tile_total * samples_per_tile));
846         else if(!background && samples > 0 && total_samples != USHRT_MAX)
847                 progress = ((float)samples) / total_samples;
848         else
849                 progress = 0.0;
850 }
851
852 void BlenderSession::update_bake_progress()
853 {
854         float progress;
855         int sample, samples_per_task, parts_total;
856
857         sample = session->progress.get_sample();
858         samples_per_task = scene->bake_manager->num_samples;
859         parts_total = scene->bake_manager->num_parts;
860
861         if(samples_per_task)
862                 progress = ((float)sample / (float)(parts_total * samples_per_task));
863         else
864                 progress = 0.0;
865
866         if(progress != last_progress) {
867                 b_engine.update_progress(progress);
868                 last_progress = progress;
869         }
870 }
871
872 void BlenderSession::update_status_progress()
873 {
874         string timestatus, status, substatus;
875         string scene = "";
876         float progress;
877         double total_time, remaining_time = 0, render_time;
878         char time_str[128];
879         float mem_used = (float)session->stats.mem_used / 1024.0f / 1024.0f;
880         float mem_peak = (float)session->stats.mem_peak / 1024.0f / 1024.0f;
881
882         get_status(status, substatus);
883         get_progress(progress, total_time, render_time);
884
885         if(progress > 0)
886                 remaining_time = (1.0 - (double)progress) * (render_time / (double)progress);
887
888         if(background) {
889                 scene += " | " + b_scene.name();
890                 if(b_rlay_name != "")
891                         scene += ", "  + b_rlay_name;
892
893                 if(b_rview_name != "")
894                         scene += ", " + b_rview_name;
895         }
896         else {
897                 BLI_timecode_string_from_time_simple(time_str, sizeof(time_str), total_time);
898                 timestatus = "Time:" + string(time_str) + " | ";
899         }
900
901         if(remaining_time > 0) {
902                 BLI_timecode_string_from_time_simple(time_str, sizeof(time_str), remaining_time);
903                 timestatus += "Remaining:" + string(time_str) + " | ";
904         }
905
906         timestatus += string_printf("Mem:%.2fM, Peak:%.2fM", (double)mem_used, (double)mem_peak);
907
908         if(status.size() > 0)
909                 status = " | " + status;
910         if(substatus.size() > 0)
911                 status += " | " + substatus;
912
913         if(status != last_status) {
914                 b_engine.update_stats("", (timestatus + scene + status).c_str());
915                 b_engine.update_memory_stats(mem_used, mem_peak);
916                 last_status = status;
917         }
918         if(progress != last_progress) {
919                 b_engine.update_progress(progress);
920                 last_progress = progress;
921         }
922
923         if(session->progress.get_error()) {
924                 string error = session->progress.get_error_message();
925                 if(error != last_error) {
926                         /* TODO(sergey): Currently C++ RNA API doesn't let us to
927                          * use mnemonic name for the variable. Would be nice to
928                          * have this figured out.
929                          *
930                          * For until then, 1 << 5 means RPT_ERROR.
931                          */
932                         b_engine.report(1 << 5, error.c_str());
933                         b_engine.error_set(error.c_str());
934                         last_error = error;
935                 }
936         }
937 }
938
939 void BlenderSession::tag_update()
940 {
941         /* tell blender that we want to get another update callback */
942         b_engine.tag_update();
943 }
944
945 void BlenderSession::tag_redraw()
946 {
947         if(background) {
948                 /* update stats and progress, only for background here because
949                  * in 3d view we do it in draw for thread safety reasons */
950                 update_status_progress();
951
952                 /* offline render, redraw if timeout passed */
953                 if(time_dt() - last_redraw_time > 1.0) {
954                         b_engine.tag_redraw();
955                         last_redraw_time = time_dt();
956                 }
957         }
958         else {
959                 /* tell blender that we want to redraw */
960                 b_engine.tag_redraw();
961         }
962 }
963
964 void BlenderSession::test_cancel()
965 {
966         /* test if we need to cancel rendering */
967         if(background)
968                 if(b_engine.test_break())
969                         session->progress.set_cancel("Cancelled");
970 }
971
972 /* builtin image file name is actually an image datablock name with
973  * absolute sequence frame number concatenated via '@' character
974  *
975  * this function splits frame from builtin name
976  */
977 int BlenderSession::builtin_image_frame(const string &builtin_name)
978 {
979         int last = builtin_name.find_last_of('@');
980         return atoi(builtin_name.substr(last + 1, builtin_name.size() - last - 1).c_str());
981 }
982
983 void BlenderSession::builtin_image_info(const string &builtin_name, void *builtin_data, bool &is_float, int &width, int &height, int &depth, int &channels)
984 {
985         /* empty image */
986         is_float = false;
987         width = 0;
988         height = 0;
989         depth = 0;
990         channels = 0;
991
992         if(!builtin_data)
993                 return;
994
995         /* recover ID pointer */
996         PointerRNA ptr;
997         RNA_id_pointer_create((ID*)builtin_data, &ptr);
998         BL::ID b_id(ptr);
999
1000         if(b_id.is_a(&RNA_Image)) {
1001                 /* image data */
1002                 BL::Image b_image(b_id);
1003
1004                 is_float = b_image.is_float();
1005                 width = b_image.size()[0];
1006                 height = b_image.size()[1];
1007                 depth = 1;
1008                 channels = b_image.channels();
1009         }
1010         else if(b_id.is_a(&RNA_Object)) {
1011                 /* smoke volume data */
1012                 BL::Object b_ob(b_id);
1013                 BL::SmokeDomainSettings b_domain = object_smoke_domain_find(b_ob);
1014
1015                 if(!b_domain)
1016                         return;
1017
1018                 if(builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_DENSITY) ||
1019                    builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_FLAME))
1020                         channels = 1;
1021                 else if(builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_COLOR))
1022                         channels = 4;
1023                 else
1024                         return;
1025
1026                 int3 resolution = get_int3(b_domain.domain_resolution());
1027                 int amplify = (b_domain.use_high_resolution())? b_domain.amplify() + 1: 1;
1028
1029                 width = resolution.x * amplify;
1030                 height = resolution.y * amplify;
1031                 depth = resolution.z * amplify;
1032
1033                 is_float = true;
1034         }
1035         else {
1036                 /* TODO(sergey): Check we're indeed in shader node tree. */
1037                 PointerRNA ptr;
1038                 RNA_pointer_create(NULL, &RNA_Node, builtin_data, &ptr);
1039                 BL::Node b_node(ptr);
1040                 if(b_node.is_a(&RNA_ShaderNodeTexPointDensity)) {
1041                         BL::ShaderNodeTexPointDensity b_point_density_node(b_node);
1042                         channels = 4;
1043                         width = height = depth = b_point_density_node.resolution();
1044                         is_float = true;
1045                 }
1046         }
1047 }
1048
1049 bool BlenderSession::builtin_image_pixels(const string &builtin_name, void *builtin_data, unsigned char *pixels)
1050 {
1051         if(!builtin_data)
1052                 return false;
1053
1054         int frame = builtin_image_frame(builtin_name);
1055
1056         PointerRNA ptr;
1057         RNA_id_pointer_create((ID*)builtin_data, &ptr);
1058         BL::Image b_image(ptr);
1059
1060         int width = b_image.size()[0];
1061         int height = b_image.size()[1];
1062         int channels = b_image.channels();
1063
1064         unsigned char *image_pixels;
1065         image_pixels = image_get_pixels_for_frame(b_image, frame);
1066         size_t num_pixels = ((size_t)width) * height;
1067
1068         if(image_pixels) {
1069                 memcpy(pixels, image_pixels, num_pixels * channels * sizeof(unsigned char));
1070                 MEM_freeN(image_pixels);
1071         }
1072         else {
1073                 if(channels == 1) {
1074                         memset(pixels, 0, num_pixels * sizeof(unsigned char));
1075                 }
1076                 else {
1077                         unsigned char *cp = pixels;
1078                         for(size_t i = 0; i < num_pixels; i++, cp += channels) {
1079                                 cp[0] = 255;
1080                                 cp[1] = 0;
1081                                 cp[2] = 255;
1082                                 if(channels == 4)
1083                                         cp[3] = 255;
1084                         }
1085                 }
1086         }
1087
1088         /* premultiply, byte images are always straight for blender */
1089         unsigned char *cp = pixels;
1090         for(size_t i = 0; i < num_pixels; i++, cp += channels) {
1091                 cp[0] = (cp[0] * cp[3]) >> 8;
1092                 cp[1] = (cp[1] * cp[3]) >> 8;
1093                 cp[2] = (cp[2] * cp[3]) >> 8;
1094         }
1095
1096         return true;
1097 }
1098
1099 bool BlenderSession::builtin_image_float_pixels(const string &builtin_name, void *builtin_data, float *pixels)
1100 {
1101         if(!builtin_data)
1102                 return false;
1103
1104         PointerRNA ptr;
1105         RNA_id_pointer_create((ID*)builtin_data, &ptr);
1106         BL::ID b_id(ptr);
1107
1108         if(b_id.is_a(&RNA_Image)) {
1109                 /* image data */
1110                 BL::Image b_image(b_id);
1111                 int frame = builtin_image_frame(builtin_name);
1112
1113                 int width = b_image.size()[0];
1114                 int height = b_image.size()[1];
1115                 int channels = b_image.channels();
1116
1117                 float *image_pixels;
1118                 image_pixels = image_get_float_pixels_for_frame(b_image, frame);
1119                 size_t num_pixels = ((size_t)width) * height;
1120
1121                 if(image_pixels) {
1122                         memcpy(pixels, image_pixels, num_pixels * channels * sizeof(float));
1123                         MEM_freeN(image_pixels);
1124                 }
1125                 else {
1126                         if(channels == 1) {
1127                                 memset(pixels, 0, num_pixels * sizeof(float));
1128                         }
1129                         else {
1130                                 float *fp = pixels;
1131                                 for(int i = 0; i < num_pixels; i++, fp += channels) {
1132                                         fp[0] = 1.0f;
1133                                         fp[1] = 0.0f;
1134                                         fp[2] = 1.0f;
1135                                         if(channels == 4)
1136                                                 fp[3] = 1.0f;
1137                                 }
1138                         }
1139                 }
1140
1141                 return true;
1142         }
1143         else if(b_id.is_a(&RNA_Object)) {
1144                 /* smoke volume data */
1145                 BL::Object b_ob(b_id);
1146                 BL::SmokeDomainSettings b_domain = object_smoke_domain_find(b_ob);
1147
1148                 if(!b_domain)
1149                         return false;
1150
1151                 int3 resolution = get_int3(b_domain.domain_resolution());
1152                 int length, amplify = (b_domain.use_high_resolution())? b_domain.amplify() + 1: 1;
1153
1154                 int width = resolution.x * amplify;
1155                 int height = resolution.y * amplify;
1156                 int depth = resolution.z * amplify;
1157                 size_t num_pixels = ((size_t)width) * height * depth;
1158
1159                 if(builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_DENSITY)) {
1160                         SmokeDomainSettings_density_grid_get_length(&b_domain.ptr, &length);
1161
1162                         if(length == num_pixels) {
1163                                 SmokeDomainSettings_density_grid_get(&b_domain.ptr, pixels);
1164                                 return true;
1165                         }
1166                 }
1167                 else if(builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_FLAME)) {
1168                         /* this is in range 0..1, and interpreted by the OpenGL smoke viewer
1169                          * as 1500..3000 K with the first part faded to zero density */
1170                         SmokeDomainSettings_flame_grid_get_length(&b_domain.ptr, &length);
1171
1172                         if(length == num_pixels) {
1173                                 SmokeDomainSettings_flame_grid_get(&b_domain.ptr, pixels);
1174                                 return true;
1175                         }
1176                 }
1177                 else if(builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_COLOR)) {
1178                         /* the RGB is "premultiplied" by density for better interpolation results */
1179                         SmokeDomainSettings_color_grid_get_length(&b_domain.ptr, &length);
1180
1181                         if(length == num_pixels*4) {
1182                                 SmokeDomainSettings_color_grid_get(&b_domain.ptr, pixels);
1183                                 return true;
1184                         }
1185                 }
1186
1187                 fprintf(stderr, "Cycles error: unexpected smoke volume resolution, skipping\n");
1188         }
1189         else {
1190                 /* TODO(sergey): Check we're indeed in shader node tree. */
1191                 PointerRNA ptr;
1192                 RNA_pointer_create(NULL, &RNA_Node, builtin_data, &ptr);
1193                 BL::Node b_node(ptr);
1194                 if(b_node.is_a(&RNA_ShaderNodeTexPointDensity)) {
1195                         BL::ShaderNodeTexPointDensity b_point_density_node(b_node);
1196                         int length;
1197                         b_point_density_node.calc_point_density(b_scene, &length, &pixels);
1198                 }
1199         }
1200
1201         return false;
1202 }
1203
1204 CCL_NAMESPACE_END
1205