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